From dc16cbe01b10f1a3f7a234701b2ca64dafacab31 Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Sun, 28 Jun 2026 00:11:26 +0200 Subject: [PATCH 1/3] Java: model org.apache.commons.xml XmlFactories as safe XXE sources 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) --- ...2026-08-02-apache-commons-xml-factories.md | 5 ++ .../java/frameworks/apache/CommonsXml.qll | 22 +++++++ .../semmle/code/java/security/XmlParsers.qll | 19 ++++++ .../security/CWE-611/XmlFactoriesTests.java | 62 +++++++++++++++++++ .../test/query-tests/security/CWE-611/options | 2 +- .../org/apache/commons/xml/XmlFactories.java | 39 ++++++++++++ 6 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 java/ql/lib/change-notes/2026-08-02-apache-commons-xml-factories.md create mode 100644 java/ql/test/query-tests/security/CWE-611/XmlFactoriesTests.java create mode 100644 java/ql/test/stubs/apache-commons-xml-0.1.0/org/apache/commons/xml/XmlFactories.java diff --git a/java/ql/lib/change-notes/2026-08-02-apache-commons-xml-factories.md b/java/ql/lib/change-notes/2026-08-02-apache-commons-xml-factories.md new file mode 100644 index 000000000000..6ec4686065be --- /dev/null +++ b/java/ql/lib/change-notes/2026-08-02-apache-commons-xml-factories.md @@ -0,0 +1,5 @@ +--- +category: feature +--- +* Factories returned by the Apache Commons XML (`org.apache.commons.xml.XmlFactories`) hardening library are now recognized as safely configured by the XXE query. +* A new extensible class `SafeXmlFactorySource` was added to `semmle.code.java.security.XmlParsers` for modeling sources of pre-hardened JAXP factories. diff --git a/java/ql/lib/semmle/code/java/frameworks/apache/CommonsXml.qll b/java/ql/lib/semmle/code/java/frameworks/apache/CommonsXml.qll index 163bd773dad0..aa6d840a0782 100644 --- a/java/ql/lib/semmle/code/java/frameworks/apache/CommonsXml.qll +++ b/java/ql/lib/semmle/code/java/frameworks/apache/CommonsXml.qll @@ -90,3 +90,25 @@ private module SafeDigesterFlowConfig implements DataFlow::ConfigSig { } private module SafeDigesterFlow = DataFlow::Global; + +/** + * A call to one of the `org.apache.commons.xml.XmlFactories.newXxxFactory()` methods + * of the Apache Commons XML library. + * + * Every such method returns a fresh JAXP factory that has already been hardened against + * XML external entity (XXE) attacks, so any parser created from it is treated as safe. + * + * `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 XXE results. + */ +private class CommonsXmlSafeXmlFactory extends SafeXmlFactorySource, MethodCall { + CommonsXmlSafeXmlFactory() { + this.getMethod().getDeclaringType().hasQualifiedName("org.apache.commons.xml", "XmlFactories") and + this.getMethod() + .hasName([ + "newDocumentBuilderFactory", "newSAXParserFactory", "newXMLInputFactory", + "newTransformerFactory", "newSchemaFactory", "newXPathFactory" + ]) + } +} diff --git a/java/ql/lib/semmle/code/java/security/XmlParsers.qll b/java/ql/lib/semmle/code/java/security/XmlParsers.qll index 602076996a77..4a30ded19e3a 100644 --- a/java/ql/lib/semmle/code/java/security/XmlParsers.qll +++ b/java/ql/lib/semmle/code/java/security/XmlParsers.qll @@ -56,6 +56,15 @@ abstract class ParserConfig extends MethodCall { } } +/** + * An expression that evaluates to a JAXP parser factory (such as a + * `DocumentBuilderFactory` or `SAXParserFactory`) that has already been hardened + * against XML external entity (XXE) attacks, for example by a helper library. + * + * Extend this class to model additional sources of pre-hardened JAXP factories. + */ +abstract class SafeXmlFactorySource extends Expr { } + /* * https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxp-documentbuilderfactory-saxparserfactory-and-dom4j */ @@ -156,6 +165,8 @@ private class DocumentBuilderConstruction extends MethodCall { private predicate safeDocumentBuilderFactoryNode(DataFlow::Node src) { src.asExpr() instanceof SafeDocumentBuilderFactory + or + src.asExpr().(SafeXmlFactorySource).getType() instanceof DocumentBuilderFactory } private module SafeDocumentBuilderFactoryToDocumentBuilderConstructionFlow = @@ -219,6 +230,8 @@ class XmlInputFactoryStreamReader extends XmlParserCall { private predicate safeXmlInputFactoryNode(DataFlow::Node src) { src.asExpr() instanceof SafeXmlInputFactory + or + src.asExpr().(SafeXmlFactorySource).getType() instanceof XmlInputFactory } private module SafeXmlInputFactoryToXmlInputFactoryReaderFlow = @@ -456,6 +469,8 @@ class SafeSaxParserFactory extends VarAccess { private predicate safeSaxParserFactoryNode(DataFlow::Node src) { src.asExpr() instanceof SafeSaxParserFactory + or + src.asExpr().(SafeXmlFactorySource).getType() instanceof SaxParserFactory } private module SafeSaxParserFactoryToNewSaxParserFlow = @@ -831,6 +846,8 @@ class TransformerFactoryConfig extends TransformerConfig { private predicate safeTransformerFactoryNode(DataFlow::Node src) { src.asExpr() instanceof SafeTransformerFactory + or + src.asExpr().(SafeXmlFactorySource).getType() instanceof TransformerFactory } private module SafeTransformerFactoryFlow = DataFlow::SimpleGlobal; @@ -920,6 +937,8 @@ class SchemaFactoryNewSchema extends XmlParserCall { private predicate safeSchemaFactoryNode(DataFlow::Node src) { src.asExpr() instanceof SafeSchemaFactory + or + src.asExpr().(SafeXmlFactorySource).getType() instanceof SchemaFactory } private module SafeSchemaFactoryToSchemaFactoryNewSchemaFlow = diff --git a/java/ql/test/query-tests/security/CWE-611/XmlFactoriesTests.java b/java/ql/test/query-tests/security/CWE-611/XmlFactoriesTests.java new file mode 100644 index 000000000000..ebb1b54e3382 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-611/XmlFactoriesTests.java @@ -0,0 +1,62 @@ +import java.net.Socket; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.stream.XMLInputFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; + +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; + +import org.apache.commons.xml.XmlFactories; + +// Every factory returned by `org.apache.commons.xml.XmlFactories` is already hardened against +// XXE, so the parsers created from them must not be reported. +public class XmlFactoriesTests { + + public void hardenedDocumentBuilder(Socket sock) throws Exception { + DocumentBuilderFactory factory = XmlFactories.newDocumentBuilderFactory(); + DocumentBuilder builder = factory.newDocumentBuilder(); + builder.parse(sock.getInputStream()); // safe + } + + public void hardenedDocumentBuilderChained(Socket sock) throws Exception { + XmlFactories.newDocumentBuilderFactory().newDocumentBuilder().parse(sock.getInputStream()); // safe + } + + public void hardenedSaxParser(Socket sock) throws Exception { + SAXParserFactory factory = XmlFactories.newSAXParserFactory(); + SAXParser parser = factory.newSAXParser(); + parser.parse(sock.getInputStream(), new DefaultHandler()); // safe + } + + public void hardenedSaxParserXmlReader(Socket sock) throws Exception { + SAXParser parser = XmlFactories.newSAXParserFactory().newSAXParser(); + XMLReader reader = parser.getXMLReader(); + reader.parse(new org.xml.sax.InputSource(sock.getInputStream())); // safe + } + + public void hardenedXmlInputFactory(Socket sock) throws Exception { + XMLInputFactory factory = XmlFactories.newXMLInputFactory(); + factory.createXMLStreamReader(sock.getInputStream()); // safe + factory.createXMLEventReader(sock.getInputStream()); // safe + } + + public void hardenedTransformer(Socket sock) throws Exception { + TransformerFactory tf = XmlFactories.newTransformerFactory(); + Transformer transformer = tf.newTransformer(); + transformer.transform(new StreamSource(sock.getInputStream()), null); // safe + tf.newTransformer(new StreamSource(sock.getInputStream())); // safe + } + + public void hardenedSchema(Socket sock) throws Exception { + SchemaFactory factory = XmlFactories.newSchemaFactory(); + Schema schema = factory.newSchema(new StreamSource(sock.getInputStream())); // safe + } +} diff --git a/java/ql/test/query-tests/security/CWE-611/options b/java/ql/test/query-tests/security/CWE-611/options index 190e6b2af0c6..1d6e3c40b307 100644 --- a/java/ql/test/query-tests/security/CWE-611/options +++ b/java/ql/test/query-tests/security/CWE-611/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/jdom-1.1.3:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/simple-xml-2.7.1:${testdir}/../../../stubs/jaxb-api-2.3.1:${testdir}/../../../stubs/jaxen-1.2.0:${testdir}/../../../stubs/apache-commons-digester3-3.2:${testdir}/../../../stubs/servlet-api-2.4/:${testdir}/../../../stubs/rundeck-api-java-client-13.2:${testdir}/../../../stubs/springframework-5.8.x/:${testdir}/../../../stubs/mdht-1.2.0/:${testdir}/../../../stubs/woodstox-core-6.4.0 +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/jdom-1.1.3:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/simple-xml-2.7.1:${testdir}/../../../stubs/jaxb-api-2.3.1:${testdir}/../../../stubs/jaxen-1.2.0:${testdir}/../../../stubs/apache-commons-digester3-3.2:${testdir}/../../../stubs/servlet-api-2.4/:${testdir}/../../../stubs/rundeck-api-java-client-13.2:${testdir}/../../../stubs/springframework-5.8.x/:${testdir}/../../../stubs/mdht-1.2.0/:${testdir}/../../../stubs/woodstox-core-6.4.0:${testdir}/../../../stubs/apache-commons-xml-0.1.0 diff --git a/java/ql/test/stubs/apache-commons-xml-0.1.0/org/apache/commons/xml/XmlFactories.java b/java/ql/test/stubs/apache-commons-xml-0.1.0/org/apache/commons/xml/XmlFactories.java new file mode 100644 index 000000000000..733a3f5aad33 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-xml-0.1.0/org/apache/commons/xml/XmlFactories.java @@ -0,0 +1,39 @@ +// Minimal stub of org.apache.commons.xml.XmlFactories for testing purposes + +package org.apache.commons.xml; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.stream.XMLInputFactory; +import javax.xml.transform.TransformerFactory; +import javax.xml.validation.SchemaFactory; +import javax.xml.xpath.XPathFactory; + +public final class XmlFactories { + + public static DocumentBuilderFactory newDocumentBuilderFactory() { + return null; + } + + public static SAXParserFactory newSAXParserFactory() { + return null; + } + + public static SchemaFactory newSchemaFactory() { + return null; + } + + public static TransformerFactory newTransformerFactory() { + return null; + } + + public static XMLInputFactory newXMLInputFactory() { + return null; + } + + public static XPathFactory newXPathFactory() { + return null; + } + + private XmlFactories() {} +} From 5f1e8b894fe52ff0fb4275fa1c8510cee41e4a0e Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Tue, 18 Aug 2026 10:07:09 +0200 Subject: [PATCH 2/3] Java: update newSchemaFactory to the merged Commons XML 0.1.0 API apache/commons-xml#32 replaced the no-argument newSchemaFactory() with newSchemaFactory(String schemaLanguage), without keeping an overload. Update the 0.1.0 stub and the XXE test accordingly, as suggested by Copilot. The QL model matches the method by name, so no query or library changes are needed. Assisted-By: Claude Fable 5 --- .../test/query-tests/security/CWE-611/XmlFactoriesTests.java | 3 ++- .../org/apache/commons/xml/XmlFactories.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/java/ql/test/query-tests/security/CWE-611/XmlFactoriesTests.java b/java/ql/test/query-tests/security/CWE-611/XmlFactoriesTests.java index ebb1b54e3382..c5fcc18a3daa 100644 --- a/java/ql/test/query-tests/security/CWE-611/XmlFactoriesTests.java +++ b/java/ql/test/query-tests/security/CWE-611/XmlFactoriesTests.java @@ -1,5 +1,6 @@ import java.net.Socket; +import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.SAXParser; @@ -56,7 +57,7 @@ public void hardenedTransformer(Socket sock) throws Exception { } public void hardenedSchema(Socket sock) throws Exception { - SchemaFactory factory = XmlFactories.newSchemaFactory(); + SchemaFactory factory = XmlFactories.newSchemaFactory(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = factory.newSchema(new StreamSource(sock.getInputStream())); // safe } } diff --git a/java/ql/test/stubs/apache-commons-xml-0.1.0/org/apache/commons/xml/XmlFactories.java b/java/ql/test/stubs/apache-commons-xml-0.1.0/org/apache/commons/xml/XmlFactories.java index 733a3f5aad33..0b820c958214 100644 --- a/java/ql/test/stubs/apache-commons-xml-0.1.0/org/apache/commons/xml/XmlFactories.java +++ b/java/ql/test/stubs/apache-commons-xml-0.1.0/org/apache/commons/xml/XmlFactories.java @@ -19,7 +19,7 @@ public static SAXParserFactory newSAXParserFactory() { return null; } - public static SchemaFactory newSchemaFactory() { + public static SchemaFactory newSchemaFactory(final String schemaLanguage) { return null; } From 546e64d51e3bc279b7d8fc5edd81245ba7ea3af0 Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Mon, 31 Aug 2026 10:39:49 +0200 Subject: [PATCH 3/3] Java: update the Commons XML model to the commons-secure-xml 1.0.0 API The library was renamed from commons-xml to commons-secure-xml: the org.apache.commons.xml.XmlFactories entry point is replaced by six per-factory classes in org.apache.commons.xml.secure, whose static new* methods mirror the JAXP factory entry points and all return hardened factories. Assisted-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01BiNxFje3KZrioKjQTcBCyk --- .../2026-08-02-apache-commons-secure-xml.md | 5 +++ ...2026-08-02-apache-commons-xml-factories.md | 5 --- .../java/frameworks/apache/CommonsXml.qll | 28 ++++++++----- ...ests.java => SecureXmlFactoriesTests.java} | 36 +++++++++++------ .../test/query-tests/security/CWE-611/options | 2 +- .../secure/SecureDocumentBuilderFactory.java | 34 ++++++++++++++++ .../xml/secure/SecureSAXParserFactory.java | 34 ++++++++++++++++ .../xml/secure/SecureSchemaFactory.java | 23 +++++++++++ .../xml/secure/SecureTransformerFactory.java | 22 +++++++++++ .../xml/secure/SecureXMLInputFactory.java | 26 +++++++++++++ .../xml/secure/SecureXPathFactory.java | 28 +++++++++++++ .../org/apache/commons/xml/XmlFactories.java | 39 ------------------- 12 files changed, 216 insertions(+), 66 deletions(-) create mode 100644 java/ql/lib/change-notes/2026-08-02-apache-commons-secure-xml.md delete mode 100644 java/ql/lib/change-notes/2026-08-02-apache-commons-xml-factories.md rename java/ql/test/query-tests/security/CWE-611/{XmlFactoriesTests.java => SecureXmlFactoriesTests.java} (54%) create mode 100644 java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureDocumentBuilderFactory.java create mode 100644 java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureSAXParserFactory.java create mode 100644 java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureSchemaFactory.java create mode 100644 java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureTransformerFactory.java create mode 100644 java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureXMLInputFactory.java create mode 100644 java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureXPathFactory.java delete mode 100644 java/ql/test/stubs/apache-commons-xml-0.1.0/org/apache/commons/xml/XmlFactories.java diff --git a/java/ql/lib/change-notes/2026-08-02-apache-commons-secure-xml.md b/java/ql/lib/change-notes/2026-08-02-apache-commons-secure-xml.md new file mode 100644 index 000000000000..898255b12458 --- /dev/null +++ b/java/ql/lib/change-notes/2026-08-02-apache-commons-secure-xml.md @@ -0,0 +1,5 @@ +--- +category: feature +--- +* Factories returned by the Apache Commons Secure XML (`org.apache.commons.xml.secure`) hardening library's `SecureDocumentBuilderFactory`, `SecureSAXParserFactory`, `SecureXMLInputFactory`, `SecureTransformerFactory` and `SecureSchemaFactory` classes are now recognized as safely configured by the XXE query. +* A new extensible class `SafeXmlFactorySource` was added to `semmle.code.java.security.XmlParsers` for modeling sources of pre-hardened JAXP factories. diff --git a/java/ql/lib/change-notes/2026-08-02-apache-commons-xml-factories.md b/java/ql/lib/change-notes/2026-08-02-apache-commons-xml-factories.md deleted file mode 100644 index 6ec4686065be..000000000000 --- a/java/ql/lib/change-notes/2026-08-02-apache-commons-xml-factories.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: feature ---- -* Factories returned by the Apache Commons XML (`org.apache.commons.xml.XmlFactories`) hardening library are now recognized as safely configured by the XXE query. -* A new extensible class `SafeXmlFactorySource` was added to `semmle.code.java.security.XmlParsers` for modeling sources of pre-hardened JAXP factories. diff --git a/java/ql/lib/semmle/code/java/frameworks/apache/CommonsXml.qll b/java/ql/lib/semmle/code/java/frameworks/apache/CommonsXml.qll index aa6d840a0782..fa570b0b61ae 100644 --- a/java/ql/lib/semmle/code/java/frameworks/apache/CommonsXml.qll +++ b/java/ql/lib/semmle/code/java/frameworks/apache/CommonsXml.qll @@ -92,23 +92,31 @@ private module SafeDigesterFlowConfig implements DataFlow::ConfigSig { private module SafeDigesterFlow = DataFlow::Global; /** - * A call to one of the `org.apache.commons.xml.XmlFactories.newXxxFactory()` methods - * of the Apache Commons XML library. + * A call to one of the static factory methods of the `org.apache.commons.xml.secure` + * `SecureXxxFactory` classes of the Apache Commons Secure XML library. * - * Every such method returns a fresh JAXP factory that has already been hardened against - * XML external entity (XXE) attacks, so any parser created from it is treated as safe. + * These methods mirror the JAXP factory entry points (`newInstance`, `newDefaultInstance`, + * `newNSInstance`, `newFactory`, ...) and every one of them returns a fresh JAXP factory + * that has already been hardened against XML external entity (XXE) attacks, so any parser + * created from it is treated as safe. * - * `newXPathFactory` is matched for completeness, but the XXE model has no `XPathFactory` + * `SecureXPathFactory` 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 XXE results. */ -private class CommonsXmlSafeXmlFactory extends SafeXmlFactorySource, MethodCall { - CommonsXmlSafeXmlFactory() { - this.getMethod().getDeclaringType().hasQualifiedName("org.apache.commons.xml", "XmlFactories") and +private class CommonsSecureXmlFactory extends SafeXmlFactorySource, MethodCall { + CommonsSecureXmlFactory() { + this.getMethod() + .getDeclaringType() + .hasQualifiedName("org.apache.commons.xml.secure", + [ + "SecureDocumentBuilderFactory", "SecureSAXParserFactory", "SecureXMLInputFactory", + "SecureTransformerFactory", "SecureSchemaFactory", "SecureXPathFactory" + ]) and this.getMethod() .hasName([ - "newDocumentBuilderFactory", "newSAXParserFactory", "newXMLInputFactory", - "newTransformerFactory", "newSchemaFactory", "newXPathFactory" + "newDefaultInstance", "newDefaultNSInstance", "newInstance", "newNSInstance", + "newDefaultFactory", "newFactory" ]) } } diff --git a/java/ql/test/query-tests/security/CWE-611/XmlFactoriesTests.java b/java/ql/test/query-tests/security/CWE-611/SecureXmlFactoriesTests.java similarity index 54% rename from java/ql/test/query-tests/security/CWE-611/XmlFactoriesTests.java rename to java/ql/test/query-tests/security/CWE-611/SecureXmlFactoriesTests.java index c5fcc18a3daa..77c6dccfed73 100644 --- a/java/ql/test/query-tests/security/CWE-611/XmlFactoriesTests.java +++ b/java/ql/test/query-tests/security/CWE-611/SecureXmlFactoriesTests.java @@ -15,49 +15,63 @@ import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; -import org.apache.commons.xml.XmlFactories; +import org.apache.commons.xml.secure.SecureDocumentBuilderFactory; +import org.apache.commons.xml.secure.SecureSAXParserFactory; +import org.apache.commons.xml.secure.SecureSchemaFactory; +import org.apache.commons.xml.secure.SecureTransformerFactory; +import org.apache.commons.xml.secure.SecureXMLInputFactory; -// Every factory returned by `org.apache.commons.xml.XmlFactories` is already hardened against -// XXE, so the parsers created from them must not be reported. -public class XmlFactoriesTests { +// Every factory returned by the `org.apache.commons.xml.secure.SecureXxxFactory` classes is +// already hardened against XXE, so the parsers created from them must not be reported. +public class SecureXmlFactoriesTests { public void hardenedDocumentBuilder(Socket sock) throws Exception { - DocumentBuilderFactory factory = XmlFactories.newDocumentBuilderFactory(); + DocumentBuilderFactory factory = SecureDocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); builder.parse(sock.getInputStream()); // safe } public void hardenedDocumentBuilderChained(Socket sock) throws Exception { - XmlFactories.newDocumentBuilderFactory().newDocumentBuilder().parse(sock.getInputStream()); // safe + SecureDocumentBuilderFactory.newDefaultNSInstance().newDocumentBuilder().parse(sock.getInputStream()); // safe } public void hardenedSaxParser(Socket sock) throws Exception { - SAXParserFactory factory = XmlFactories.newSAXParserFactory(); + SAXParserFactory factory = SecureSAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); parser.parse(sock.getInputStream(), new DefaultHandler()); // safe } public void hardenedSaxParserXmlReader(Socket sock) throws Exception { - SAXParser parser = XmlFactories.newSAXParserFactory().newSAXParser(); + SAXParser parser = SecureSAXParserFactory.newNSInstance().newSAXParser(); XMLReader reader = parser.getXMLReader(); reader.parse(new org.xml.sax.InputSource(sock.getInputStream())); // safe } public void hardenedXmlInputFactory(Socket sock) throws Exception { - XMLInputFactory factory = XmlFactories.newXMLInputFactory(); + XMLInputFactory factory = SecureXMLInputFactory.newFactory(); factory.createXMLStreamReader(sock.getInputStream()); // safe factory.createXMLEventReader(sock.getInputStream()); // safe } + public void hardenedXmlInputFactoryDefault(Socket sock) throws Exception { + XMLInputFactory factory = SecureXMLInputFactory.newDefaultFactory(); + factory.createXMLStreamReader(sock.getInputStream()); // safe + } + public void hardenedTransformer(Socket sock) throws Exception { - TransformerFactory tf = XmlFactories.newTransformerFactory(); + TransformerFactory tf = SecureTransformerFactory.newInstance(); Transformer transformer = tf.newTransformer(); transformer.transform(new StreamSource(sock.getInputStream()), null); // safe tf.newTransformer(new StreamSource(sock.getInputStream())); // safe } + public void hardenedTransformerDefault(Socket sock) throws Exception { + TransformerFactory tf = SecureTransformerFactory.newDefaultInstance(); + tf.newTransformer(new StreamSource(sock.getInputStream())); // safe + } + public void hardenedSchema(Socket sock) throws Exception { - SchemaFactory factory = XmlFactories.newSchemaFactory(XMLConstants.W3C_XML_SCHEMA_NS_URI); + SchemaFactory factory = SecureSchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = factory.newSchema(new StreamSource(sock.getInputStream())); // safe } } diff --git a/java/ql/test/query-tests/security/CWE-611/options b/java/ql/test/query-tests/security/CWE-611/options index 1d6e3c40b307..c7186f87c849 100644 --- a/java/ql/test/query-tests/security/CWE-611/options +++ b/java/ql/test/query-tests/security/CWE-611/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/jdom-1.1.3:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/simple-xml-2.7.1:${testdir}/../../../stubs/jaxb-api-2.3.1:${testdir}/../../../stubs/jaxen-1.2.0:${testdir}/../../../stubs/apache-commons-digester3-3.2:${testdir}/../../../stubs/servlet-api-2.4/:${testdir}/../../../stubs/rundeck-api-java-client-13.2:${testdir}/../../../stubs/springframework-5.8.x/:${testdir}/../../../stubs/mdht-1.2.0/:${testdir}/../../../stubs/woodstox-core-6.4.0:${testdir}/../../../stubs/apache-commons-xml-0.1.0 +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/jdom-1.1.3:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/simple-xml-2.7.1:${testdir}/../../../stubs/jaxb-api-2.3.1:${testdir}/../../../stubs/jaxen-1.2.0:${testdir}/../../../stubs/apache-commons-digester3-3.2:${testdir}/../../../stubs/servlet-api-2.4/:${testdir}/../../../stubs/rundeck-api-java-client-13.2:${testdir}/../../../stubs/springframework-5.8.x/:${testdir}/../../../stubs/mdht-1.2.0/:${testdir}/../../../stubs/woodstox-core-6.4.0:${testdir}/../../../stubs/apache-commons-secure-xml-1.0.0 diff --git a/java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureDocumentBuilderFactory.java b/java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureDocumentBuilderFactory.java new file mode 100644 index 000000000000..22011e425aa2 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureDocumentBuilderFactory.java @@ -0,0 +1,34 @@ +// Minimal stub of org.apache.commons.xml.secure.SecureDocumentBuilderFactory for testing purposes + +package org.apache.commons.xml.secure; + +import javax.xml.parsers.DocumentBuilderFactory; + +public final class SecureDocumentBuilderFactory { + + public static DocumentBuilderFactory newDefaultInstance() { + return null; + } + + public static DocumentBuilderFactory newDefaultNSInstance() { + return null; + } + + public static DocumentBuilderFactory newInstance() { + return null; + } + + public static DocumentBuilderFactory newInstance(final String factoryClassName, final ClassLoader classLoader) { + return null; + } + + public static DocumentBuilderFactory newNSInstance() { + return null; + } + + public static DocumentBuilderFactory newNSInstance(final String factoryClassName, final ClassLoader classLoader) { + return null; + } + + private SecureDocumentBuilderFactory() {} +} diff --git a/java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureSAXParserFactory.java b/java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureSAXParserFactory.java new file mode 100644 index 000000000000..4a0adcb44617 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureSAXParserFactory.java @@ -0,0 +1,34 @@ +// Minimal stub of org.apache.commons.xml.secure.SecureSAXParserFactory for testing purposes + +package org.apache.commons.xml.secure; + +import javax.xml.parsers.SAXParserFactory; + +public final class SecureSAXParserFactory { + + public static SAXParserFactory newDefaultInstance() { + return null; + } + + public static SAXParserFactory newDefaultNSInstance() { + return null; + } + + public static SAXParserFactory newInstance() { + return null; + } + + public static SAXParserFactory newInstance(final String factoryClassName, final ClassLoader classLoader) { + return null; + } + + public static SAXParserFactory newNSInstance() { + return null; + } + + public static SAXParserFactory newNSInstance(final String factoryClassName, final ClassLoader classLoader) { + return null; + } + + private SecureSAXParserFactory() {} +} diff --git a/java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureSchemaFactory.java b/java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureSchemaFactory.java new file mode 100644 index 000000000000..5c0d5ac258de --- /dev/null +++ b/java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureSchemaFactory.java @@ -0,0 +1,23 @@ +// Minimal stub of org.apache.commons.xml.secure.SecureSchemaFactory for testing purposes + +package org.apache.commons.xml.secure; + +import javax.xml.validation.SchemaFactory; + +public final class SecureSchemaFactory { + + public static SchemaFactory newDefaultInstance() { + return null; + } + + public static SchemaFactory newInstance(final String schemaLanguage) { + return null; + } + + public static SchemaFactory newInstance(final String schemaLanguage, final String factoryClassName, + final ClassLoader classLoader) { + return null; + } + + private SecureSchemaFactory() {} +} diff --git a/java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureTransformerFactory.java b/java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureTransformerFactory.java new file mode 100644 index 000000000000..c51bb648ca10 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureTransformerFactory.java @@ -0,0 +1,22 @@ +// Minimal stub of org.apache.commons.xml.secure.SecureTransformerFactory for testing purposes + +package org.apache.commons.xml.secure; + +import javax.xml.transform.TransformerFactory; + +public final class SecureTransformerFactory { + + public static TransformerFactory newDefaultInstance() { + return null; + } + + public static TransformerFactory newInstance() { + return null; + } + + public static TransformerFactory newInstance(final String factoryClassName, final ClassLoader classLoader) { + return null; + } + + private SecureTransformerFactory() {} +} diff --git a/java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureXMLInputFactory.java b/java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureXMLInputFactory.java new file mode 100644 index 000000000000..7116d3c14ae4 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureXMLInputFactory.java @@ -0,0 +1,26 @@ +// Minimal stub of org.apache.commons.xml.secure.SecureXMLInputFactory for testing purposes + +package org.apache.commons.xml.secure; + +import javax.xml.stream.XMLInputFactory; + +public final class SecureXMLInputFactory { + + public static XMLInputFactory newDefaultFactory() { + return null; + } + + public static XMLInputFactory newFactory() { + return null; + } + + public static XMLInputFactory newFactory(final String factoryId, final ClassLoader classLoader) { + return null; + } + + public static XMLInputFactory newInstance() { + return null; + } + + private SecureXMLInputFactory() {} +} diff --git a/java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureXPathFactory.java b/java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureXPathFactory.java new file mode 100644 index 000000000000..b7bc969bf7f7 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-secure-xml-1.0.0/org/apache/commons/xml/secure/SecureXPathFactory.java @@ -0,0 +1,28 @@ +// Minimal stub of org.apache.commons.xml.secure.SecureXPathFactory for testing purposes + +package org.apache.commons.xml.secure; + +import javax.xml.xpath.XPathFactory; +import javax.xml.xpath.XPathFactoryConfigurationException; + +public final class SecureXPathFactory { + + public static XPathFactory newDefaultInstance() { + return null; + } + + public static XPathFactory newInstance() { + return null; + } + + public static XPathFactory newInstance(final String uri) throws XPathFactoryConfigurationException { + return null; + } + + public static XPathFactory newInstance(final String uri, final String factoryClassName, final ClassLoader classLoader) + throws XPathFactoryConfigurationException { + return null; + } + + private SecureXPathFactory() {} +} diff --git a/java/ql/test/stubs/apache-commons-xml-0.1.0/org/apache/commons/xml/XmlFactories.java b/java/ql/test/stubs/apache-commons-xml-0.1.0/org/apache/commons/xml/XmlFactories.java deleted file mode 100644 index 0b820c958214..000000000000 --- a/java/ql/test/stubs/apache-commons-xml-0.1.0/org/apache/commons/xml/XmlFactories.java +++ /dev/null @@ -1,39 +0,0 @@ -// Minimal stub of org.apache.commons.xml.XmlFactories for testing purposes - -package org.apache.commons.xml; - -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.SAXParserFactory; -import javax.xml.stream.XMLInputFactory; -import javax.xml.transform.TransformerFactory; -import javax.xml.validation.SchemaFactory; -import javax.xml.xpath.XPathFactory; - -public final class XmlFactories { - - public static DocumentBuilderFactory newDocumentBuilderFactory() { - return null; - } - - public static SAXParserFactory newSAXParserFactory() { - return null; - } - - public static SchemaFactory newSchemaFactory(final String schemaLanguage) { - return null; - } - - public static TransformerFactory newTransformerFactory() { - return null; - } - - public static XMLInputFactory newXMLInputFactory() { - return null; - } - - public static XPathFactory newXPathFactory() { - return null; - } - - private XmlFactories() {} -}