ppkarwasz commented on code in PR #42:
URL: https://github.com/apache/commons-xml/pull/42#discussion_r3857483707


##########
src/test/java/org/apache/commons/xml/EntityResolverFloorTest.java:
##########
@@ -352,7 +361,41 @@ void transformerDeniesUnlisted() {
                     .transform(AttackTestSupport.streamSource("<root/>"), new 
StreamResult(sink));
             
assertFalse(sink.toString().contains(AttackTestSupport.LEAKED_MARKER), 
"unlisted stylesheet import leaked");
         } catch (final TransformerException blocked) {
-            // Acceptable: rejected at compile rather than resolved to empty.
+            // Throwing is an acceptable outcome, since it doesn't leak the 
marker.
+        }
+    }
+
+    @Test
+    @Tag("trax")
+    void transformerParsesOptedInImportHardened() {
+        // The opted-in module carries an external DTD reference; parsed on 
the floor the DTD is empty, so its entity cannot expand into the output.
+        final TransformerFactory factory = hardenedTransformerFactory();
+        factory.setURIResolver((href, base) ->
+                href != null && href.endsWith("included.xsl") ? 
AttackTestSupport.resourceSource("included-with-entity.xsl") : null);
+        try {
+            final StringWriter sink = new StringWriter();
+            
factory.newTemplates(AttackTestSupport.resourceSource("with-import.xsl")).newTransformer()
+                    .transform(AttackTestSupport.streamSource("<root/>"), new 
StreamResult(sink));
+            
assertFalse(sink.toString().contains(AttackTestSupport.LEAKED_MARKER), 
"opted-in stylesheet import leaked its external entity");
+        } catch (final TransformerException blocked) {

Review Comment:
   It turns out the failure never happens: I probed every CI combination (JDK 
8–25 × XSLTC, Xalan, Saxon, over both SAX parsers) and the transform always 
completes — the floor resolves to a well-formed empty document that every 
implementation accepts, and the entity left undeclared by an emptied DTD is 
only a validity violation, which non-validating parsers skip. Since not 
throwing is the invariant, d2a3568 drops the try/catch and uses 
`assertDoesNotThrow` in all three tests, with comments explaining why the 
outcome is deterministic.



##########
src/test/java/org/apache/commons/xml/EntityResolverFloorTest.java:
##########
@@ -352,7 +361,41 @@ void transformerDeniesUnlisted() {
                     .transform(AttackTestSupport.streamSource("<root/>"), new 
StreamResult(sink));
             
assertFalse(sink.toString().contains(AttackTestSupport.LEAKED_MARKER), 
"unlisted stylesheet import leaked");
         } catch (final TransformerException blocked) {
-            // Acceptable: rejected at compile rather than resolved to empty.
+            // Throwing is an acceptable outcome, since it doesn't leak the 
marker.
+        }
+    }
+
+    @Test
+    @Tag("trax")
+    void transformerParsesOptedInImportHardened() {
+        // The opted-in module carries an external DTD reference; parsed on 
the floor the DTD is empty, so its entity cannot expand into the output.
+        final TransformerFactory factory = hardenedTransformerFactory();
+        factory.setURIResolver((href, base) ->
+                href != null && href.endsWith("included.xsl") ? 
AttackTestSupport.resourceSource("included-with-entity.xsl") : null);
+        try {
+            final StringWriter sink = new StringWriter();
+            
factory.newTemplates(AttackTestSupport.resourceSource("with-import.xsl")).newTransformer()
+                    .transform(AttackTestSupport.streamSource("<root/>"), new 
StreamResult(sink));
+            
assertFalse(sink.toString().contains(AttackTestSupport.LEAKED_MARKER), 
"opted-in stylesheet import leaked its external entity");
+        } catch (final TransformerException blocked) {
+            // Throwing is an acceptable outcome, since it doesn't leak the 
marker.
+        }
+    }
+
+    @Test
+    @Tag("trax")
+    void transformerParsesOptedInDocumentHardened() {
+        // Same contract on the runtime document() channel, which reaches a 
different internal reader than the compile-time import.
+        final TransformerFactory factory = hardenedTransformerFactory();
+        factory.setURIResolver((href, base) ->
+                href != null && href.endsWith("referenced.xml") ? 
AttackTestSupport.resourceSource("referenced-with-entity.xml") : null);
+        try {
+            final StringWriter sink = new StringWriter();
+            
factory.newTemplates(AttackTestSupport.resourceSource("with-document.xsl")).newTransformer()
+                    .transform(AttackTestSupport.streamSource("<root/>"), new 
StreamResult(sink));
+            
assertFalse(sink.toString().contains(AttackTestSupport.LEAKED_MARKER), 
"opted-in document() resource leaked its external entity");
+        } catch (final TransformerException blocked) {
+            // Throwing is an acceptable outcome, since it doesn't leak the 
marker.

Review Comment:
   Same resolution as above: the failure turned out to be impossible on the 
tested matrix, so d2a3568 asserts the strict no-throw/no-leak outcome here too.



##########
src/test/java/org/apache/commons/xml/EntityResolverFloorTest.java:
##########
@@ -352,7 +361,41 @@ void transformerDeniesUnlisted() {
                     .transform(AttackTestSupport.streamSource("<root/>"), new 
StreamResult(sink));
             
assertFalse(sink.toString().contains(AttackTestSupport.LEAKED_MARKER), 
"unlisted stylesheet import leaked");
         } catch (final TransformerException blocked) {
-            // Acceptable: rejected at compile rather than resolved to empty.
+            // Throwing is an acceptable outcome, since it doesn't leak the 
marker.
+        }
+    }
+
+    @Test
+    @Tag("trax")
+    void transformerParsesOptedInImportHardened() {
+        // The opted-in module carries an external DTD reference; parsed on 
the floor the DTD is empty, so its entity cannot expand into the output.
+        final TransformerFactory factory = hardenedTransformerFactory();
+        factory.setURIResolver((href, base) ->
+                href != null && href.endsWith("included.xsl") ? 
AttackTestSupport.resourceSource("included-with-entity.xsl") : null);
+        try {
+            final StringWriter sink = new StringWriter();
+            
factory.newTemplates(AttackTestSupport.resourceSource("with-import.xsl")).newTransformer()
+                    .transform(AttackTestSupport.streamSource("<root/>"), new 
StreamResult(sink));
+            
assertFalse(sink.toString().contains(AttackTestSupport.LEAKED_MARKER), 
"opted-in stylesheet import leaked its external entity");
+        } catch (final TransformerException blocked) {

Review Comment:
   I rechecked and apparently these throws are now stale: both Xalan and Saxon 
are happy with the kind of empty resource they receive.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to