diff --git a/README.md b/README.md
index ffe967342..4474d38f3 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@ Maven Usage
org.cyclonedx
cyclonedx-core-java
- 10.1.0
+ 11.0.1
```
diff --git a/pom.xml b/pom.xml
index f224e5aa0..3ccfbb540 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,7 +23,7 @@
org.cyclonedx
cyclonedx-core-java
jar
- 11.1.0-SNAPSHOT
+ 11.0.1-SNAPSHOT
CycloneDX Core (Java)
The CycloneDX core module provides a model representation of the BOM along with utilities to assist in creating, parsing, and validating BOMs.
diff --git a/src/main/java/org/cyclonedx/CycloneDxSchema.java b/src/main/java/org/cyclonedx/CycloneDxSchema.java
index 94a796ad8..1e942272a 100644
--- a/src/main/java/org/cyclonedx/CycloneDxSchema.java
+++ b/src/main/java/org/cyclonedx/CycloneDxSchema.java
@@ -271,6 +271,9 @@ private Schema getXmlSchema16() throws SAXException {
public Schema getXmlSchema(InputStream... inputStreams) throws SAXException {
final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+ schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
+ schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
+ schemaFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
final Source[] schemaFiles = new Source[inputStreams.length];
for (int i = 0; i < inputStreams.length; i++) {
schemaFiles[i] = new StreamSource(inputStreams[i]);
diff --git a/src/main/java/org/cyclonedx/parsers/XmlParser.java b/src/main/java/org/cyclonedx/parsers/XmlParser.java
index 119e5fd69..fb482ba43 100644
--- a/src/main/java/org/cyclonedx/parsers/XmlParser.java
+++ b/src/main/java/org/cyclonedx/parsers/XmlParser.java
@@ -338,6 +338,7 @@ private Document createSecureDocument(InputSource in) throws ParserConfiguration
DocumentBuilderFactory df = DocumentBuilderFactory.newInstance();
df.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
df.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
+ df.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
DocumentBuilder builder = df.newDocumentBuilder();
return builder.parse(in);
}
diff --git a/src/test/java/org/cyclonedx/BomXmlGeneratorTest.java b/src/test/java/org/cyclonedx/BomXmlGeneratorTest.java
index bf041845b..fda392819 100644
--- a/src/test/java/org/cyclonedx/BomXmlGeneratorTest.java
+++ b/src/test/java/org/cyclonedx/BomXmlGeneratorTest.java
@@ -18,12 +18,11 @@
*/
package org.cyclonedx;
-import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.cyclonedx.exception.ParseException;
import org.cyclonedx.generators.BomGeneratorFactory;
import org.cyclonedx.generators.json.BomJsonGenerator;
-import org.cyclonedx.generators.xml.*;
+import org.cyclonedx.generators.xml.BomXmlGenerator;
import org.cyclonedx.model.Attribute;
import org.cyclonedx.model.Bom;
import org.cyclonedx.model.Component;
@@ -46,20 +45,26 @@
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.w3c.dom.Document;
+
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
+import java.util.Objects;
import java.util.UUID;
import java.util.stream.Stream;
-import java.util.Objects;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
public class BomXmlGeneratorTest {
@@ -670,9 +675,9 @@ public void testIssue408Regression_externalReferenceBom() throws Exception {
@Test
public void testXxeProtection() {
- assertThrows(ParseException.class, () -> {
- createCommonBomXml("/security/xxe-protection.xml");
- });
+ assertThatExceptionOfType(ParseException.class)
+ .isThrownBy(() -> createCommonBomXml("/security/xxe-protection.xml"))
+ .withMessageContaining("not allowed due to restriction set by the accessExternalDTD property");
}
@Test
diff --git a/src/test/java/org/cyclonedx/parsers/XmlParserTest.java b/src/test/java/org/cyclonedx/parsers/XmlParserTest.java
index c444fc5a5..0074cdbd3 100644
--- a/src/test/java/org/cyclonedx/parsers/XmlParserTest.java
+++ b/src/test/java/org/cyclonedx/parsers/XmlParserTest.java
@@ -18,13 +18,14 @@
*/
package org.cyclonedx.parsers;
+import org.apache.commons.io.IOUtils;
import org.cyclonedx.Version;
+import org.cyclonedx.exception.ParseException;
import org.cyclonedx.model.Bom;
import org.cyclonedx.model.Component;
import org.cyclonedx.model.Component.Type;
import org.cyclonedx.model.Dependency;
import org.cyclonedx.model.ExternalReference;
-import org.cyclonedx.model.License;
import org.cyclonedx.model.LicenseChoice;
import org.cyclonedx.model.OrganizationalEntity;
import org.cyclonedx.model.Pedigree;
@@ -65,13 +66,16 @@
import org.cyclonedx.model.license.Acknowledgement;
import org.cyclonedx.model.license.Expression;
import org.junit.jupiter.api.Test;
+
import java.io.File;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
@@ -746,4 +750,19 @@ public void testIssue492Regression() throws Exception {
final Bom bom = getXmlBom("regression/issue492.xml");
assertEquals(2, bom.getMetadata().getTools().size());
}
+
+ @Test
+ void validateShouldNotBeVulnerableToXxe() throws Exception {
+ final byte[] bomBytes;
+ try (final InputStream bomInputStream = getClass().getResourceAsStream("/security/xxe-protection.xml")) {
+ assertThat(bomInputStream).isNotNull();
+ bomBytes = IOUtils.toByteArray(bomInputStream);
+ }
+
+ final List validationFailures = new XmlParser().validate(bomBytes);
+ assertThat(validationFailures).extracting(Throwable::getMessage).allSatisfy(
+ failureMessage -> assertThat(failureMessage)
+ .contains("not allowed due to restriction set by the accessExternalDTD property"));
+ }
+
}
diff --git a/src/test/resources/security/xxe-protection.xml b/src/test/resources/security/xxe-protection.xml
index f91bdcb49..3de89c238 100644
--- a/src/test/resources/security/xxe-protection.xml
+++ b/src/test/resources/security/xxe-protection.xml
@@ -1,5 +1,5 @@
- %sp; %param1; %exfil;]>
+ %sp; %param1; %exfil;]>