CVE-2023-41034: Improper Restriction of XML External Entity Reference (CWE-611)
value: Eclipse Leshan is a device management server and client Java implementation. In affected versions DDFFileParser` and `DefaultDDFFileValidator` (and so `ObjectLoader`) are vulnerable to `XXE Attacks`. A DDF file is a LWM2M format used to store LWM2M object description. Leshan users are impacted only if they parse untrusted DDF files (e.g. if they let external users provide their own model), in that case they MUST upgrade to fixed version. If you parse only trusted DDF file and validate only with trusted xml schema, upgrading is not mandatory.  This issue has been fixed in versions 1.5.0 and 2.0.0-M13. Users are advised to upgrade. There are no known workarounds for this vulnerability.
CWE description: The product processes an XML document that can contain XML entities with URIs that resolve to documents outside of the intended sphere of control, causing the product to embed incorrect documents into its output.
CVSS v3 base score: 9.8
Published: 2023-08-31T18:15Z
Repository: https://github.com/eclipse-leshan/leshan
Language: Java
Files changed: leshan-core/src/main/java/org/eclipse/leshan/core/model/DDFFileParser.java, leshan-core/src/main/java/org/eclipse/leshan/core/model/DefaultDDFFileValidator.java
Commit date: 2023-08-29 11:43:49 +0200
Commit message: Make DDFFileParser and DefaultDDFFileValidator safer.

Diff: diff --git a/leshan-core/src/main/java/org/eclipse/leshan/core/model/DDFFileParser.java b/leshan-core/src/main/java/org/eclipse/leshan/core/model/DDFFileParser.java
index ae073217..93b1ccaf 100644
--- a/leshan-core/src/main/java/org/eclipse/leshan/core/model/DDFFileParser.java
+++ b/leshan-core/src/main/java/org/eclipse/leshan/core/model/DDFFileParser.java
@@ -22,10 +22,11 @@ import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
+import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 
 import org.eclipse.leshan.core.LwM2m.LwM2mVersion;
@@ -73,16 +74,43 @@ public class DDFFileParser {
     public DDFFileParser(DDFFileValidatorFactory ddfFileValidatorFactory) {
         this(null, ddfFileValidatorFactory);
     }
 
     private DDFFileParser(DDFFileValidator ddfValidator, DDFFileValidatorFactory ddfFileValidatorFactory) {
-        factory = DocumentBuilderFactory.newInstance();
-        factory.setNamespaceAware(true);
+        this.factory = createDocumentBuilderFactory();
         this.ddfValidator = ddfValidator;
         this.ddfValidatorFactory = ddfFileValidatorFactory;
     }
 
+    protected DocumentBuilderFactory createDocumentBuilderFactory() {
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        try {
+            // Create Safe DocumentBuilderFactory (not vulnerable to XXE Attacks)
+            // -----------------------------------------------------------------
+            // There is several recommendation from different source we try to apply all, even if some are maybe
+            // redundant.
+
+            // from :
+            // https://semgrep.dev/docs/cheat-sheets/java-xxe/
+            factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+
+            // from :
+            // https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxp-documentbuilderfactory-saxparserfactory-and-dom4j
+            factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); // Disable DTDs
+            factory.setXIncludeAware(false); // Disable XML Inclusions
+
+            // from :
+            // https://community.veracode.com/s/article/Java-Remediation-Guidance-for-XXE
+            factory.setExpandEntityReferences(false); // disable expand entity reference nodes
+
+        } catch (ParserConfigurationException e) {
+            throw new IllegalStateException("Unable to create DocumentBuilderFactory", e);
+        }
+        factory.setNamespaceAware(true);
+        return factory;
+    }
+
     /**
      * Parse a DDF file.
      *
      * @throws InvalidDDFFileException if DDF file is not a valid.
      * @throws IOException see {@link FileInputStream#FileInputStream(File)} or
diff --git a/leshan-core/src/main/java/org/eclipse/leshan/core/model/DefaultDDFFileValidator.java b/leshan-core/src/main/java/org/eclipse/leshan/core/model/DefaultDDFFileValidator.java
index fa93f930..7352275e 100644
--- a/leshan-core/src/main/java/org/eclipse/leshan/core/model/DefaultDDFFileValidator.java
+++ b/leshan-core/src/main/java/org/eclipse/leshan/core/model/DefaultDDFFileValidator.java
@@ -28,10 +28,12 @@ import javax.xml.validation.Validator;
 
 import org.eclipse.leshan.core.LwM2m.LwM2mVersion;
 import org.eclipse.leshan.core.util.Validate;
 import org.w3c.dom.Node;
 import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
 
 /**
  * A DDF File Validator.
  * <p>
  * Validate a DDF File against the embedded LWM2M schema.
@@ -93,9 +95,32 @@ public class DefaultDDFFileValidator implements DDFFileValidator {
      * @throws SAXException see {@link SchemaFactory#newSchema(Source)}
      */
     protected Schema getEmbeddedLwM2mSchema() throws SAXException {
         InputStream inputStream = DDFFileValidator.class.getResourceAsStream(schema);
         Source source = new StreamSource(inputStream);
-        SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+        SchemaFactory schemaFactory = createSchemaFactory();
         return schemaFactory.newSchema(source);
     }
+
+    protected SchemaFactory createSchemaFactory() {
+        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+        try {
+            // Create Safe SchemaFactory (not vulnerable to XXE Attacks)
+            // --------------------------------------------------------
+            // There is several recommendation from different source we try to apply all, even if some are maybe
+            // redundant.
+
+            // from :
+            // https://semgrep.dev/docs/cheat-sheets/java-xxe/
+            factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+
+            // from :
+            // https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#schemafactory
+            factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
+            factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
+
+        } catch (SAXNotRecognizedException | SAXNotSupportedException e) {
+            throw new IllegalStateException("Unable to create SchemaFactory", e);
+        }
+        return factory;
+    }
 }

Vulnerable code:         factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Fixed code: import javax.xml.XMLConstants;
        this.factory = createDocumentBuilderFactory();
    protected DocumentBuilderFactory createDocumentBuilderFactory() {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        try {
            // Create Safe DocumentBuilderFactory (not vulnerable to XXE Attacks)
            // -----------------------------------------------------------------
            // There is several recommendation from different source we try to apply all, even if some are maybe
            // redundant.

            // from :
            // https://semgrep.dev/docs/cheat-sheets/java-xxe/
            factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

            // from :
            // https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxp-documentbuilderfactory-saxparserfactory-and-dom4j
            factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); // Disable DTDs
            factory.setXIncludeAware(false); // Disable XML Inclusions

            // from :
            // https://community.veracode.com/s/article/Java-Remediation-Guidance-for-XXE
            factory.setExpandEntityReferences(false); // disable expand entity reference nodes

        } catch (ParserConfigurationException e) {
            throw new IllegalStateException("Unable to create DocumentBuilderFactory", e);
        }
        factory.setNamespaceAware(true);
        return factory;
    }

import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
        SchemaFactory schemaFactory = createSchemaFactory();

    protected SchemaFactory createSchemaFactory() {
        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        try {
            // Create Safe SchemaFactory (not vulnerable to XXE Attacks)
            // --------------------------------------------------------
            // There is several recommendation from different source we try to apply all, even if some are maybe
            // redundant.

            // from :
            // https://semgrep.dev/docs/cheat-sheets/java-xxe/
            factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

            // from :
            // https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#schemafactory
            factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
            factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");

        } catch (SAXNotRecognizedException | SAXNotSupportedException e) {
            throw new IllegalStateException("Unable to create SchemaFactory", e);
        }
        return factory;
    }