Skip to content

Java: model org.apache.commons.xml XmlFactories as safe XXE sources - #22269

Open
ppkarwasz wants to merge 1 commit into
github:mainfrom
ppkarwasz:feat/xml-commons
Open

Java: model org.apache.commons.xml XmlFactories as safe XXE sources#22269
ppkarwasz wants to merge 1 commit into
github:mainfrom
ppkarwasz:feat/xml-commons

Conversation

@ppkarwasz

Copy link
Copy Markdown

Description

We are about to publish the first release of Apache Commons XML, a new Apache Commons component that provides secure-by-default creation of JAXP factories. Its org.apache.commons.xml.XmlFactories entry point returns factories that are hardened against XXE and SSRF regardless of which JAXP implementation is on the classpath (JDK, Android, Xalan, Xerces, Woodstox, Saxon-HE). This differs from the usual approach of setting implementation-specific hardening features on whatever factory newInstance() returns: when the implementation does not support a given feature, that approach silently fails open, whereas Commons XML detects the implementation and applies a hardening strategy known to work for it, failing closed otherwise.

Beyond the technical guarantee, an equally important goal of the library is to reduce the security-report noise around XML parsing of trusted documents, such as configuration files. Maintainers of libraries that parse such files regularly receive reports of alleged XXE vulnerabilities, and each SAST tool expects a slightly different set of hardening features before it stops flagging a JAXP factory call. Centralizing the hardening in one well-audited place gives maintainers a single answer to those reports, and gives SAST tools a single API to recognize.

Why open this PR before the first release?

That last point is exactly why we are opening this PR now rather than after adoption picks up. The library only delivers its value if security tooling recognizes it: otherwise every adoption creates alerts instead of removing them. We saw this with the library's prototype, copernik-xml-factory: when I tested it in the Apache Log4j project I maintain, CodeQL raised an XXE alert on the very code the library exists to make safe (apache/logging-log4j2#4144 (comment)), and every future adopter would have to triage and dismiss the same false positive or ship a custom model pack.

Modeling the library ahead of its 0.1.0 release means early adopters get correct CodeQL results from day one. The API surface modeled here (the six static newXxxFactory() methods) is final for the first release, so the model is not chasing a moving target and the apache/commons-xml#32 API correction I proposed today does not require changes in the CodeQL code.

Concretely: every factory returned by org.apache.commons.xml.XmlFactories is already hardened against XML external entity (XXE) attacks, but the XXE query (java/xxe, CWE-611) does not know this and reports parsers created from these factories as vulnerable.

This PR teaches the XXE query that such factories are safely configured:

  • Adds a new public extensible class SafeXmlFactorySource to semmle.code.java.security.XmlParsers, representing an expression that evaluates to a JAXP factory that is already hardened against XXE (for example by a helper library). It is wired into the five existing safe-factory flow sources (DocumentBuilderFactory, SAXParserFactory, XMLInputFactory, TransformerFactory, SchemaFactory), dispatching on the static type of the expression.
  • Extends semmle.code.java.frameworks.apache.CommonsXml (which already models Commons Digester for XXE) with a SafeXmlFactorySource subclass matching calls to the XmlFactories.newXxxFactory() methods. newXPathFactory is matched for completeness, but the XXE model has no XPathFactory safety chain (the XXE sink for XPath is the document being evaluated, not the factory), so it currently has no effect on results.

Note

I do not write QL myself. This PR was created with the help of Claude Code (claude-opus-4-8 and claude-fable-5). I have reviewed every change semantically, that is, which calls are modeled and why they are safe to treat as hardened, but I cannot vouch for QL idiom or style, so feedback on that level is especially welcome.

Tests

  • New test file java/ql/test/query-tests/security/CWE-611/XmlFactoriesTests.java covering parsers created from each of the hardened factories (direct, chained, and via XMLReader). All cases are safe, so XXE.expected is unchanged; the test fails with new #select rows if any case is still flagged.
  • New stub java/ql/test/stubs/apache-commons-xml-0.1.0/ following the existing apache-commons-<name>-<version> naming convention, added to the CWE-611 extractor classpath.
  • codeql test run java/ql/test/query-tests/security/CWE-611 passes (1/1).

Checklist

  • Change note added (java/ql/lib/change-notes/2026-08-02-apache-commons-xml-factories.md, category feature since SafeXmlFactorySource is a new public API).
  • QL files autoformatted (codeql query format --check-only passes).
  • No compiler warnings; no internal libraries, getAQlClass, or regexp matching on toString.
  • Overlay annotations valid (python config/add-overlay-annotations.py --check java passes).
  • QLDoc added for the new public class and predicates.

Recognize the hardened JAXP factories returned by
`org.apache.commons.xml.XmlFactories` (Apache Commons XML) as safely
configured, so parsers created from them are no longer reported by the
XXE query (CWE-611).

Adds an extensible `SafeXmlFactorySource` class to XmlParsers.qll and
wires it into the five existing safe-factory flow sources
(DocumentBuilderFactory, SAXParserFactory, XMLInputFactory,
TransformerFactory, SchemaFactory). `newXPathFactory` is matched for
completeness but has no XXE safety chain to feed. The framework model
lives in the existing frameworks/apache/CommonsXml.qll.

Includes a test stub, safe-case tests, and a change note.

Assisted-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 2, 2026 19:00
@ppkarwasz
ppkarwasz requested a review from a team as a code owner August 2, 2026 19:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Apache Commons XML factories as pre-hardened XXE-safe sources in Java analysis.

Changes:

  • Introduces an extensible safe-factory source model.
  • Models all six XmlFactories factory methods.
  • Adds stubs, XXE regression tests, and a change note.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
XmlFactories.java Adds the Commons XML test stub.
XmlFactoriesTests.java Tests safe parser flows from hardened factories.
options Adds the stub to the test classpath.
XmlParsers.qll Adds and connects the safe-factory extension point.
CommonsXml.qll Models Commons XML factory calls.
2026-08-02-apache-commons-xml-factories.md Documents the feature.

return null;
}

public static SchemaFactory newSchemaFactory() {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the reminder: I'll merge both suggestions as soon as the apache/commons-xml#32 is merged itself.

Since the factory method is matched by name, not by signature, this will not have any effect on the QL code.

}

public void hardenedSchema(Socket sock) throws Exception {
SchemaFactory factory = XmlFactories.newSchemaFactory();

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above (#22269 (comment))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants