Give OpenPDF's HTML module a two-column grid ledger whose total an inline script writes, and the PDF comes back with Hosting120.00Support80.00 on one line, a bold Total, and no figure after it. That run used 3.0.5, released on 22 May 2026 by the LibrePDF project, whose library began as a fork of iText 4.2.0. The ledger leads this post and five more problems follow, each one run against those jars or traced to the source that documents it.
We work at Iron Software, and the end of this article covers our library, IronPDF.
What Happens to Flexbox, Grid and Script in openpdf-html?
They are ignored. The core library's HTMLWorker parser has been deprecated since 2.1.0, and the openpdf-html module built for HTML is a Flying Saucer fork from June 2025 whose README says Flying Saucer set out to render XHTML with CSS 2.1 in plain Java, simpler than a browser engine. That README still marks HTML5 as in progress and lists JavaScript as a roadmap item. In the 3.0.5 jar, the CSSName property table holds 127 names, display, float and border-collapse among them, with none for flexbox, grid or gap.
import org.openpdf.pdf.ITextRenderer;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class FlexGridScript {
public static void main(String[] args) throws Exception {
// A flex row, a two-column grid and a script that writes the total, as a browser template would have them.
String html = "<html><head><style>"
+ ".row { display: flex; gap: 16px; }"
+ ".card { flex: 1; border: 1px solid #999; padding: 8px; }"
+ ".ledger { display: grid; grid-template-columns: 3fr 1fr; }"
+ "</style></head><body>"
+ "<div class='row'><div class='card'>North</div><div class='card'>South</div>"
+ "<div class='card' id='east'></div></div>"
+ "<div class='ledger'><span>Hosting</span><span>120.00</span>"
+ "<span>Support</span><span>80.00</span><b>Total</b><b id='sum'></b></div>"
+ "<script>document.getElementById('east').textContent = 'East';"
+ "document.getElementById('sum').textContent = (120 + 80).toFixed(2);</script>"
+ "</body></html>";
try (OutputStream out = new FileOutputStream("flex-grid-script.pdf")) {
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(html);
renderer.layout();
renderer.createPDF(out);
}
}
}
Opened in a viewer, the 1,233-byte page shows two boxes stacked down the left edge, North over South, with their text starting at x = 48.8 and their borders spanning the full text width, so the flex row never formed. Below them sits an empty bordered strip where East belonged, since no script ran, and the ledger reads as the single line quoted at the top. Browser-built templates and script-drawn charts end up the same way. The module's layout model stays CSS 2.1, so columns come from tables or floats and every total is computed in Java first.
Why Does Encryption Throw NoClassDefFoundError?
Because Bouncy Castle is optional in the POM and required at run time. The 3.0.5 core pulls in exactly one runtime library, Brotli4j at version 1.23.0, and leaves bcprov-jdk18on to the application as optional. The class below reads an existing two-page statement, sets AES-128 encryption on a PdfStamper and stamps every page.
import org.openpdf.text.Element;
import org.openpdf.text.Font;
import org.openpdf.text.FontFactory;
import org.openpdf.text.Phrase;
import org.openpdf.text.Rectangle;
import org.openpdf.text.pdf.ColumnText;
import org.openpdf.text.pdf.PdfContentByte;
import org.openpdf.text.pdf.PdfGState;
import org.openpdf.text.pdf.PdfReader;
import org.openpdf.text.pdf.PdfStamper;
import org.openpdf.text.pdf.PdfWriter;
import java.awt.Color;
import java.io.FileOutputStream;
public class StampAndEncrypt {
public static void main(String[] args) throws Exception {
PdfReader reader = new PdfReader("statement-table.pdf");
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("statement-copy.pdf"));
// The user password opens the file, and the owner password lifts the permission flags.
stamper.setEncryption("view-2026".getBytes(), "owner-2026".getBytes(),
PdfWriter.ALLOW_PRINTING, PdfWriter.ENCRYPTION_AES_128);
Font font = FontFactory.getFont(FontFactory.HELVETICA_BOLD, 60, Font.NORMAL, new Color(200, 0, 0));
PdfGState translucent = new PdfGState();
translucent.setFillOpacity(0.25f);
// getOverContent draws above the existing page, so the stamp lands on top of the table.
for (int page = 1; page <= reader.getNumberOfPages(); page++) {
Rectangle size = reader.getPageSize(page);
PdfContentByte over = stamper.getOverContent(page);
over.saveState();
over.setGState(translucent);
ColumnText.showTextAligned(over, Element.ALIGN_CENTER, new Phrase("COPY", font),
size.getWidth() / 2, size.getHeight() / 2, 45);
over.restoreState();
}
stamper.close();
reader.close();
}
}
On the declared dependencies alone, setEncryption threw NoClassDefFoundError for a Bouncy Castle ASN.1 class, ASN1OctetString on some runs and ASN1Encodable on others, from inside the PdfEncryption constructor, and a 0-byte statement-copy.pdf was left on disk. With bcprov-jdk18on 1.84 added, the same class produced a copy of about 4.5 KB, encrypted at revision 4 with the AESV2 filter, opening with view-2026, with a translucent COPY across both pages. Because the error only appears when the code path runs, a test suite that never encrypts will not catch it. The fix is an explicit Maven dependency on Bouncy Castle, and the next section explains why 1.84 is not the version to pick.
Which Advisories Touch an OpenPDF Build?
A query to OSV on 3 November 2026 found no record for either OpenPDF artifact at version 3.0.5, the core or the HTML module. The records that do come up sit one step away.
- CVE-2026-8763 scores 9.1 Critical under CVSS 3.1 (NIST): A Name Constraints bypass in Bouncy Castle 1.84, the version the OpenPDF 3.0.5 build declares.
-
CVE-2026-13506 scores 7.5 High under CVSS 3.1 (NIST): Forcing a lazy ASN.1 sequence resets the nesting-depth guard, again in 1.84. Both records are fixed in
bcprov-jdk18on1.85, released on 12 July 2026, and themasterbranch of OpenPDF still pins 1.84 on 3 November 2026. Bouncy Castle's October records, such as CVE-2026-18036, also list 1.85 and are fixed in 1.86. -
CVE-2017-9096 scores 8.8 High under CVSS 3.0 (NIST): XML external entities in iText before 5.5.12, and GHSA-86p9-x5pw-94qx widens it to the
com.lowagie:itextartifact up to 4.2.2, whose 4.2.0 tag is where OpenPDF started. Thecom.github.librepdfcoordinates are not listed, and the 3.0.5XmlParserdisables external entities.
The rest of the exposure comes from intended behavior. OpenPDF's security policy calls the library neither sandboxed nor hardened, and the project leaves every check on HTML, fonts, image locations and paths to whoever calls it, naming local file access, server-side request forgery and path traversal among the cases it does not block. In a test run, an <img> whose src was a file: URI pulled a PNG off the local disk into the PDF. Because the project asks that no CVEs be filed for such behavior, an advisory scan will not list it, and the remedy it gives is jsoup sanitizing, whitelisted src and href values and generation inside a container or sandbox. Licensing is MPL-2.0 OR LGPL-2.1+ for the core and the LGPL 2.1 or later for openpdf-html.
Who Is Affected by the Java 21 Floor?
Any team whose services run on Java 17 or below. The README sets Java 21 as the minimum for the 2.1.x line and later, and javac from JDK 17 stops on the first OpenPDF import of a 3.0.5 example.
error: cannot access Document
bad class file: openpdf-3.0.5.jar(/org/openpdf/text/Document.class)
class file has wrong version 65.0, should be 61.0
The Java 17 option is the 2.0.x branch, last released as 2.0.5 on 26 May 2025, which is older than openpdf-html itself (first shipped as 2.1.0 in June 2025) and than the move to the org.openpdf packages in 3.0.
How Much Layout Code Does a Simple Invoice Need?
Every placed element is a coordinate in points from the bottom-left corner of the page. A one-page US Letter invoice with a logo, a right-aligned title and a rule under the letterhead takes the class below.
import org.openpdf.text.Document;
import org.openpdf.text.Element;
import org.openpdf.text.Font;
import org.openpdf.text.Image;
import org.openpdf.text.PageSize;
import org.openpdf.text.Paragraph;
import org.openpdf.text.pdf.BaseFont;
import org.openpdf.text.pdf.PdfContentByte;
import org.openpdf.text.pdf.PdfWriter;
import java.io.FileOutputStream;
public class InvoiceLayout {
public static void main(String[] args) throws Exception {
// US Letter is 612 x 792 points, and the 120-point top margin leaves room for the letterhead.
Document document = new Document(PageSize.LETTER, 36, 36, 120, 36);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("invoice-layout.pdf"));
document.open();
BaseFont sans = BaseFont.createFont("fonts/LiberationSans-Regular.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
BaseFont sansBold = BaseFont.createFont("fonts/LiberationSans-Bold.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
// Absolute positions count from the bottom-left corner, so y = 792 is the top edge.
Image logo = Image.getInstance("img/logo.png");
logo.scaleToFit(150, 60);
logo.setAbsolutePosition(36, 792 - 36 - logo.getScaledHeight());
document.add(logo);
PdfContentByte canvas = writer.getDirectContent();
canvas.beginText();
canvas.setFontAndSize(sansBold, 20);
canvas.showTextAligned(Element.ALIGN_RIGHT, "Invoice 4471", 576, 730, 0);
canvas.endText();
canvas.setLineWidth(0.75f);
canvas.moveTo(36, 684);
canvas.lineTo(576, 684);
canvas.stroke();
// Flowing elements start at the top margin and wrap between the side margins.
Font body = new Font(sans, 11);
document.add(new Paragraph("Bill to: Ève Lefèvre, Rue du Rhône 12, Genève", body));
document.add(new Paragraph("Consulting, October 2026: CHF 3,200.00", body));
document.close();
}
}
The run produced a 25,786-byte Letter page with the logo scaled to 150 by 60 points at y = 696, Invoice 4471 ending at x = 576 and the rule at y = 684. Each of those numbers was chosen by hand, so a switch to A4, a taller logo or a new margin means recalculating them. Developers coming from HTML and CSS templates feel this most.
Why Does a Page X of Y Footer Take an Event Class?
OpenPDF's HeaderFooter class can print the current page number but not the total, so a footer reading Page 2 of 3 takes a PdfPageEventHelper, a PdfTemplate placed empty on each page and a write in onCloseDocument, once the total is known. In the test run, getPageNumber() returned 4 inside onCloseDocument for a three-page file, so the count written into the template has to subtract one. The three pages then shared a single 30 by 12 point form object for the total, and each read Page 1 of 3 through Page 3 of 3. Any report with running footers needs this class or the library's other route, stamping the numbers afterwards through PdfStamper when the total is already fixed.
Moving the Ledger to IronPDF for Java
For teams that would rather keep that ledger in HTML, IronPDF for Java is a commercial option that renders with Chromium, through an engine it downloads on first run or takes from a platform ironpdf-engine artifact. Our 2026.11.3 run of the first section's page laid the three cards out side by side, kept the ledger in two columns and printed the script's 200.00. It is added from Maven Central as one dependency, com.ironsoftware:ironpdf, that runs on Java 8 and later, and the 2026 line there has reached 2026.11.3, published on 3 November.
With IronPDF for Java, page numbers become a TextHeaderFooter passed to addTextFooter with Page {page} of {total-pages}, and a SecurityOptions object sets the user and owner passwords before saveAs writes the file. Markup from users still needs sanitizing before any renderer sees it.
To run your own templates through IronPDF for Java, there is a free trial.
Five Checks Before Shipping OpenPDF
OpenPDF 3.0.5 needs Java 21, an explicit and current Bouncy Castle, sanitized input, CSS 2.1 templates and hand-placed layout, and IronPDF for Java answers the HTML rendering, layout and Java-version items with a Chromium renderer on Java 8 and later.
OpenPDF, Flying Saucer, iText and Bouncy Castle are trademarks of their respective owners, we have no affiliation with any of them, and the facts above are drawn from their public repositories, Maven Central records and advisory databases.
Drafted with AI. OpenPDF code run and claims checked by the Iron Software DevRel team against com.github.librepdf:openpdf 3.0.5 and com.ironsoftware:ironpdf 2026.11.3 on 3 November 2026.
Top comments (0)