Skip to content

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

Open
anurag6569201 wants to merge 1 commit into
qa/agent-github-codeql/pr-10-22269/basefrom
qa/agent-github-codeql/pr-10-22269/head
Open

anurag6569201 wants to merge 1 commit into
qa/agent-github-codeql/pr-10-22269/basefrom
qa/agent-github-codeql/pr-10-22269/head

Conversation

@anurag6569201

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-secure-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.

Source merge-base: 5027b3627c363dd266b3e0339fd4102b7b062f8d
Source head: 619da4030f84189d0503aae5cca6b338876b9306

@shipwright-agent

Copy link
Copy Markdown

⛔ Shipwright · Blocked

Recommendation: do not merge PR #10 · Tier T2
Checks: 0 total · 0 needing attention

Next step: resolve the blocking findings before merge.

Findings (2)

  • CRITICAL CommonsSecureXmlFactory matches all overloads of newInstance/newFactory on the secure factory classes without constraining return type or parameters. · java/ql/lib/semmle/code/java/frameworks/apache/CommonsXml.qll:110
    • Fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.
  • HIGH The new 'CommonsSecureXmlFactory' class matches any method named 'newInstance', 'newDefaultInstance', 'newNSInstance', 'newDefaultNSInstance', 'newFactory', or 'newDefaultFactory' · java/ql/lib/semmle/code/java/frameworks/apache/CommonsXml.qll:110
    • Fix: Fix the review finding before release.

Fireworks usage: 15,268 input · 371 output · 15,639 total tokens · $0.0036 · 8s · 0 fix iteration(s)

Open the Shipwright check for full evidence and the audit bundle. Use /shipwright rerun to verify again.

private class CommonsSecureXmlFactory extends SafeXmlFactorySource, MethodCall {
CommonsSecureXmlFactory() {
this.getMethod()
.getDeclaringType()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Shipwright · CRITICAL

CommonsSecureXmlFactory matches all overloads of newInstance/newFactory on the secure factory classes without constraining return type or parameters.

Impact: CommonsSecureXmlFactory matches all overloads of newInstance/newFactory on the secure factory classes without constraining return type or parameters. Overloads accepting a caller-supplied factory class name and ClassLoader (e.g. SecureDocumentBuilderFactory.newInstance(String, ClassLoader), SecureSchemaFactory.newInstance(String, String, ClassLoader)) are treated as safe XXE sources even though they can return an ar…

Suggested fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.

private class CommonsSecureXmlFactory extends SafeXmlFactorySource, MethodCall {
CommonsSecureXmlFactory() {
this.getMethod()
.getDeclaringType()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Shipwright · HIGH

The new 'CommonsSecureXmlFactory' class matches any method named 'newInstance', 'newDefaultInstance', 'newNSInstance', 'newDefaultNSInstance', 'newFactory', or 'newDefaultFactory'

Impact: The new 'CommonsSecureXmlFactory' class matches any method named 'newInstance', 'newDefaultInstance', 'newNSInstance', 'newDefaultNSInstance', 'newFactory', or 'newDefaultFactory' declared on the secure factory classes, without constraining the return type. This includes overloads such as 'SecureDocumentBuilderFactory.newInstance(String, ClassLoader)' and 'SecureSchemaFactory.newInstance(String, String, ClassLoader)…

Suggested fix: Fix the review finding before release.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant