A one-line script that writes a total into a <span> is enough to show the first issue. PD4ML 4.1.2 printed the label and left the number out. PD4ML is a pure-Java HTML to PDF engine, and 4.1.2, uploaded to PD4ML's own Maven repository on 2 November 2026, is still its newest release on 4 November 2026. This post collects the issues we found running it on Java 17, with the run output and a workaround wherever we found one.
We work at Iron Software, and the end of this article covers our library, IronPDF.
Every run was unlicensed, which puts PD4ML in evaluation mode. The sections below cover every row of the table.
| Issue | Affected version | Evidence |
|---|---|---|
Script never executed, <canvas> left blank | PD4ML 4.1.2 | Run and HTML5 support matrix |
| Local files embedded from user markup | PD4ML 4.1.2, null base URL | Run and javadoc |
| CVE-2026-8763, CVE-2026-13506 and 26 more records | bcprov-jdk18on and bcpkix-jdk18on 1.84 | OSV, GHSA and CVE.org |
Grid columns and var() colours ignored | PD4ML 4.1.2 | Run and features page |
| Elements wider than 727 px clipped | PD4ML 4.1.2 default htmlWidth | Run and manual |
| PDF/A request returns a license error | PD4ML 4.1.2 without a license | Run and veraPDF |
Does PD4ML Run the Page's JavaScript?
No. PD4ML's published HTML5 compatibility table rates <script> N/A by design and explains that the code contains no script engine at all. Whatever a page's own scripts would have added stays invisible to the converter.
import com.pd4ml.PD4ML; import java.io.ByteArrayInputStream; import java.io.FileOutputStream; import java.nio.charset.StandardCharsets; public class ScriptFilledTotal { public static void main(String[] args) throws Exception { // The span is empty in the markup and a script writes the sum into it after load. String html = "<html><body><p>Open invoices: <span id='n'></span></p>" + "<script>document.getElementById('n').textContent = [12, 7, 23].reduce(function (a, b) { return a + b; });</script>" + "</body></html>"; PD4ML pd4ml = new PD4ML(); pd4ml.readHTML(new ByteArrayInputStream(html.getBytes(StandardCharsets.UTF_8)), null, "UTF-8"); try (FileOutputStream out = new FileOutputStream("open-invoices.pdf")) { pd4ml.writePDF(out); } } } open-invoices.pdf is a single A4 page whose only line reads Open invoices:. The 42 the script would have written is not there, and nothing in the run's output mentions the skipped script. A <canvas> painted by script behaves the same way, and in a separate run the canvas area came out blank, with no image or drawing on the page.
Any template that builds content in the browser runs into this, from chart libraries to totals computed client-side. The workaround is to compute values in Java and put them into the HTML, for example through setDynamicData placeholders, and to switch charts to inline <svg>, drawn as true vector graphics in STD and every higher edition according to PD4ML's products page.
Can User-Supplied HTML Read Files From the Server?
It can. When readHTML gets a null base URL, the javadoc says relative references resolve against the current working directory, and the manual warns that unrestricted HTML can make a server read local files or call internal services.
import com.pd4ml.PD4ML; import java.io.ByteArrayInputStream; import java.io.FileOutputStream; import java.nio.charset.StandardCharsets; public class UserHtmlReadsDisk { public static void main(String[] args) throws Exception { // Stands in for HTML a user submitted, which points an image at a file on the server. String userHtml = "<html><body><p>My profile</p>" + "<img src='internal/hr-badge.png'></body></html>"; // With a null base URL, relative paths resolve against the working directory. PD4ML pd4ml = new PD4ML(); pd4ml.readHTML(new ByteArrayInputStream(userHtml.getBytes(StandardCharsets.UTF_8)), null, "UTF-8"); try (FileOutputStream out = new FileOutputStream("profile.pdf")) { pd4ml.writePDF(out); } } } The working directory held internal/hr-badge.png, a 240 by 60 pixel image, and profile.pdf came out with that image embedded under My profile. A conversion service that accepts HTML from users can therefore be pointed at images on its own disk, and in two more probes a ../ path and an absolute file: URL each embedded an image from outside that directory. PD4ML has a setting for this. Passing Constants.PD4ML_ALLOWED_RESOURCE_LOCATION to setParam with a URL prefix makes it reject images, stylesheets and attachments from anywhere else, and a rerun with the prefix set to a different folder produced the page without the badge.
Which Advisories Ride Along With the Bouncy Castle Pin?
A search of OSV and GitHub's advisory database for com.pd4ml:pd4ml on 4 November 2026 returned nothing. What does show up is in Bouncy Castle. The manual's Maven snippet, still written for 4.1.1 on that date, sets both Bouncy Castle artifacts to 1.84, and OSV attaches two advisories to that bcprov version, both dated 3 August 2026 and both resolved in 1.85. CVE.org holds far more, with 28 records naming bcprov or bcpkix on 1.84, 21 from August and 7 from October, and none on 1.86.
- CVE-2026-8763, CVSS 4.0 score 9.3 Critical (Bouncy Castle, the CNA), CVSS 3.1 score 9.1 (GitHub): A certificate whose rfc822Name or URI ends in a trailing dot can slip past Name Constraints
- CVE-2026-13506, CVSS 4.0 score 8.7 High (the CNA), CVSS 3.1 score 7.5 (GitHub): Forcing a lazily parsed ASN.1 sequence resets the nesting-depth guard
The manual names the encryption and signing packages as depending on Bouncy Castle, so teams protecting or signing PDFs through PD4ML carry these until they move, and 1.86, the current release, is the one clear of them all, since records such as CVE-2026-18036 run from 1.73 to before 1.86. A separate test had PD4ML's PdfSigner sign a PDF with the 1.85 Bouncy Castle jars on the classpath.
The pin is easy to inherit without noticing. According to the manual, Maven resolves Bouncy Castle through PD4ML automatically, but the POM published for 4.1.2 lists none, so whatever versions end up in the build are the ones someone typed, and the manual's snippet offers 1.84. Maven Central doesn't carry PD4ML either, which means a Maven build first registers PD4ML's repository, pd4ml.com/maven2 in the manual.
Layout Gaps Between the Feature List and a 4.1.2 Run
PD4ML's features page says its engine lays out Flexbox and CSS Grid. In a 4.1.2 run, a display: grid container with grid-template-columns: 150px 150px 150px printed its three cards stacked down the left edge, and text coloured through var(--brand) came out black. Flexbox held up in the same session, with a space-between row spread correctly across the page.
The second layout check is width. The manual gives 727 px as the default htmlWidth, the width of the imaginary browser PD4ML lays the page out in, and a wider element is clipped at the right margin rather than scaled down.
import com.pd4ml.PD4ML; import java.io.ByteArrayInputStream; import java.io.FileOutputStream; import java.nio.charset.StandardCharsets; public class WideTableAt727 { public static void main(String[] args) throws Exception { // A 1000 px wide table, as a desktop page would lay it out, with htmlWidth left at its default. String html = "<html><body><table border='1' style='width:1000px'><tr>" + "<td>Region</td><td>Q1</td><td>Q2</td><td>Q3</td><td style='text-align:right'>Year total</td>" + "</tr></table></body></html>"; PD4ML pd4ml = new PD4ML(); pd4ml.readHTML(new ByteArrayInputStream(html.getBytes(StandardCharsets.UTF_8)), null, "UTF-8"); try (FileOutputStream out = new FileOutputStream("wide-table.pdf")) { pd4ml.writePDF(out); } } } Four of the five cells show on the page. Year total is clipped at the right margin, though its text is still in the content stream and pypdf extracts it. A rerun with pd4ml.setHtmlWidth(1000) ahead of readHTML put it back, and adjustHtmlWidth(true) from the manual sizes the window to the document instead. For grid layouts and shared design tokens, the fallback is a table or flexbox plus plain colour values in the stylesheet the PDF reads.
What Evaluation Output Looks Like
Every page of unlicensed PDF output has two blue watermark bands running vertically along its left and right margins. The manual calls evaluation mode watermarked with no restriction on functionality, yet a run asking writePDF for PdfSpec.PDFA_2B came back with an error status from getLastRenderInfo stating that the license didn't permit PDF/A. Its metadata claimed PDF/A-2B, and veraPDF 1.30.3 passed the file as PDF/A-2B, where the 4.1.1 file failed on a broken header, so a build reading that status stops on output the validator accepts. The message points at licensing, and an evaluation license, a pd4ml.lic file, can be requested from the PD4ML downloads page.
Features are also split across PD4ML's four editions. The javadoc marks TrueType embedding through useTTF and form generation as PRO features, and the products page starts DOCX at DMS and keeps PDF/UA in UA.
How IronPDF Handles Script, Grid and Wide Pages
The script, grid and width results trace back to laying out HTML without a browser, and IronPDF for Java takes the other route. Every PdfDocument render goes through a Chromium instance, so scripts on the page execute before the PDF is produced. Our 2026.11.3 run of a page with the same summing script, three grid columns and a var() colour printed 42, laid the columns out side by side and applied the colour.
When a layout is wider than the paper, the render option UseFitToPageRendering takes its pixel width and scales it to the width of one sheet, which brought a 1,000 px table inside the page next to a canvas bar in our run, and the C3.js chart example waits a second before capture.
It resolves from Maven Central as com.ironsoftware:ironpdf. Eleven versions shipped in 2026, ending with 2026.11.3 on 3 November, and nothing from Bouncy Castle turns up when Maven resolves it. IronPDF has a free trial for running your own script-heavy templates through it.
Weighing PD4ML's Issues Before Production
Missing script output, local files pulled in by untrusted markup, a Bouncy Castle 1.84 pin inside 28 CVE.org records, grid columns, custom properties and anything past 727 px lost in our runs, and a license error on a PDF/A request make up the PD4ML 4.1.2 list. For templates that depend on browser behavior, IronPDF for Java renders the same HTML in Chromium on a paper size you choose.
PD4ML is a trademark of its respective owner, we have no affiliation with its vendor, and the versions, advisories and behavior described above are taken from the vendor's public documentation, its Maven repository, public advisory databases and our own runs.
Drafted with AI. PD4ML code run and claims checked by the Iron Software DevRel team against PD4ML 4.1.2, with IronPDF APIs checked against com.ironsoftware:ironpdf 2026.11.3, on 4 November 2026.

