diff --git a/modules/saaj/src/org/apache/axis2/saaj/SOAPPartImpl.java b/modules/saaj/src/org/apache/axis2/saaj/SOAPPartImpl.java index 11d9d4f873..fe472ca89d 100644 --- a/modules/saaj/src/org/apache/axis2/saaj/SOAPPartImpl.java +++ b/modules/saaj/src/org/apache/axis2/saaj/SOAPPartImpl.java @@ -320,6 +320,11 @@ public void setContent(Source source) throws SOAPException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + // Reject DTDs and external entities so a StreamSource carrying a + // DOCTYPE cannot pull in local files or remote URLs (XXE). + inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false); + inputFactory.setProperty( + XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); XMLStreamReader reader; if (source instanceof StreamSource) { diff --git a/modules/saaj/test/org/apache/axis2/saaj/SOAPPartTest.java b/modules/saaj/test/org/apache/axis2/saaj/SOAPPartTest.java index ec25469fad..b24b87faa4 100644 --- a/modules/saaj/test/org/apache/axis2/saaj/SOAPPartTest.java +++ b/modules/saaj/test/org/apache/axis2/saaj/SOAPPartTest.java @@ -36,10 +36,15 @@ import jakarta.xml.soap.SOAPHeader; import jakarta.xml.soap.SOAPHeaderElement; import jakarta.xml.soap.SOAPMessage; +import jakarta.xml.soap.SOAPException; import jakarta.xml.soap.SOAPPart; import jakarta.xml.soap.Text; import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamSource; +import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileWriter; +import java.io.StringReader; import java.util.Iterator; /** @@ -82,6 +87,35 @@ public void testAddSource() throws Exception { getContents(iter2, ""); } + @Test + public void testSetContentRejectsExternalEntity() throws Exception { + File secret = File.createTempFile("saaj-xxe", ".txt"); + secret.deleteOnExit(); + String marker = "SAAJ_XXE_SECRET_MARKER"; + try (FileWriter w = new FileWriter(secret)) { + w.write(marker); + } + String xml = + "\n" + + " ]>\n" + + "" + + "&xxe;"; + + SOAPMessage message = MessageFactory.newInstance().createMessage(); + SOAPPart soapPart = message.getSOAPPart(); + try { + soapPart.setContent(new StreamSource(new StringReader(xml))); + message.saveChanges(); + } catch (SOAPException expected) { + // DTD rejected outright is also fine + return; + } + ByteArrayOutputStream out = new ByteArrayOutputStream(); + message.writeTo(out); + assertFalse("external entity must not be expanded into the message", + out.toString("UTF-8").contains(marker)); + } + public void getContents(Iterator iterator, String indent) { while (iterator.hasNext()) { Node node = (Node)iterator.next();