This is an automated email from the ASF dual-hosted git repository.

oscerd pushed a commit to branch camel-4.14.x
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/camel-4.14.x by this push:
     new eb40b2ff08d8 CAMEL-23783: harden camel-schematron rules 
TransformerFactory against XXE (backport to 4.14.x) (#24107)
eb40b2ff08d8 is described below

commit eb40b2ff08d89f6e968a1d3443bb43b5ca0a2cef
Author: Andrea Cosentino <[email protected]>
AuthorDate: Thu Jun 18 12:23:11 2026 +0200

    CAMEL-23783: harden camel-schematron rules TransformerFactory against XXE 
(backport to 4.14.x) (#24107)
    
    CAMEL-23783: harden camel-schematron rules TransformerFactory against XXE
    
    Signed-off-by: Andrea Cosentino <[email protected]>
    Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
---
 .../component/schematron/SchematronEndpoint.java   | 10 +++-
 .../SchematronTransformerFactoryHardeningTest.java | 56 ++++++++++++++++++++++
 .../src/test/resources/sch/schematron-xxe.sch      | 29 +++++++++++
 3 files changed, 94 insertions(+), 1 deletion(-)

diff --git 
a/components/camel-schematron/src/main/java/org/apache/camel/component/schematron/SchematronEndpoint.java
 
b/components/camel-schematron/src/main/java/org/apache/camel/component/schematron/SchematronEndpoint.java
index 4a339147b22f..3234327bef3f 100644
--- 
a/components/camel-schematron/src/main/java/org/apache/camel/component/schematron/SchematronEndpoint.java
+++ 
b/components/camel-schematron/src/main/java/org/apache/camel/component/schematron/SchematronEndpoint.java
@@ -20,7 +20,9 @@ import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.InputStream;
 
+import javax.xml.XMLConstants;
 import javax.xml.transform.Templates;
+import javax.xml.transform.TransformerConfigurationException;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.URIResolver;
 
@@ -167,7 +169,7 @@ public class SchematronEndpoint extends DefaultEndpoint {
         }
     }
 
-    private void createTransformerFactory() throws ClassNotFoundException {
+    private void createTransformerFactory() throws ClassNotFoundException, 
TransformerConfigurationException {
         // provide the class loader of this component to work in OSGi 
environments
         Class<TransformerFactory> factoryClass
                 = 
getCamelContext().getClassResolver().resolveMandatoryClass(SAXON_TRANSFORMER_FACTORY_CLASS_NAME,
@@ -175,6 +177,12 @@ public class SchematronEndpoint extends DefaultEndpoint {
 
         LOG.debug("Using TransformerFactoryClass {}", factoryClass);
         transformerFactory = 
getCamelContext().getInjector().newInstance(factoryClass);
+        // Harden the rules-compilation factory against XXE / external 
resource access, consistent with the
+        // SAXParserFactory hardening in SchematronProcessorFactory. The ISO 
skeleton stylesheets are resolved
+        // from the classpath via the URIResolver set below, so legitimate 
rule compilation is unaffected.
+        transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, 
true);
+        transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
+        
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
         transformerFactory.setURIResolver(new 
ClassPathURIResolver(Constants.SCHEMATRON_TEMPLATES_ROOT_DIR, 
this.uriResolver));
         transformerFactory.setAttribute(LINE_NUMBERING, true);
     }
diff --git 
a/components/camel-schematron/src/test/java/org/apache/camel/component/schematron/SchematronTransformerFactoryHardeningTest.java
 
b/components/camel-schematron/src/test/java/org/apache/camel/component/schematron/SchematronTransformerFactoryHardeningTest.java
new file mode 100644
index 000000000000..eab674d79b7a
--- /dev/null
+++ 
b/components/camel-schematron/src/test/java/org/apache/camel/component/schematron/SchematronTransformerFactoryHardeningTest.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.schematron;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * Verifies that the schematron rules-compilation {@code TransformerFactory} 
is hardened. Resolving a schematron
+ * endpoint compiles its rules, so these tests assert on endpoint resolution: 
legitimate rules (whose ISO skeleton
+ * stylesheets resolve from the classpath via the URIResolver) still compile, 
while rules referencing an external entity
+ * are refused rather than having the entity resolved.
+ */
+public class SchematronTransformerFactoryHardeningTest {
+
+    @Test
+    void legitimateRulesStillCompileWithHardenedFactory() throws Exception {
+        try (CamelContext ctx = new DefaultCamelContext()) {
+            ctx.start();
+            assertDoesNotThrow(
+                    () -> ctx.getEndpoint("schematron:sch/schematron-1.sch", 
SchematronEndpoint.class),
+                    "Legitimate schematron rules must still compile after 
enabling secure processing");
+        }
+    }
+
+    @Test
+    void externalEntityInRulesIsNotResolved() throws Exception {
+        try (CamelContext ctx = new DefaultCamelContext()) {
+            ctx.start();
+            // Without the hardening this rules file compiles (the external 
entity is expanded into the assert text);
+            // with FEATURE_SECURE_PROCESSING + accessExternalDTD="" the 
parser refuses the entity, so compilation
+            // (triggered on endpoint resolution) must fail instead of 
resolving it.
+            assertThrows(Exception.class,
+                    () -> ctx.getEndpoint("schematron:sch/schematron-xxe.sch", 
SchematronEndpoint.class),
+                    "Schematron rules referencing an external entity must fail 
rather than resolve the entity");
+        }
+    }
+}
diff --git 
a/components/camel-schematron/src/test/resources/sch/schematron-xxe.sch 
b/components/camel-schematron/src/test/resources/sch/schematron-xxe.sch
new file mode 100644
index 000000000000..9f28b2dfc294
--- /dev/null
+++ b/components/camel-schematron/src/test/resources/sch/schematron-xxe.sch
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<!DOCTYPE sch:schema [
+  <!ENTITY xxe SYSTEM "file:///etc/hostname">
+]>
+<sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron";>
+    <sch:pattern>
+        <sch:rule context="/">
+            <sch:assert test="true()">&xxe;</sch:assert>
+        </sch:rule>
+    </sch:pattern>
+</sch:schema>

Reply via email to