CWE-776 in APIs
- CWE ID
- CWE-776
- Category
- Input Validation
- Severity
- HIGH
- Short Name
- XML Bomb
What is CWE-776?
CWE-776, or "Improper Restriction of Recursive Entity References in DTDs (XML Entity Expansion)", describes a vulnerability where XML parsers fail to properly limit the expansion of entity references. This weakness allows attackers to craft malicious XML documents that cause exponential entity expansion, leading to denial of service through excessive CPU or memory consumption.
The vulnerability exploits how XML Document Type Definitions (DTDs) handle entity references. When an entity like &entity; is defined to reference itself or create circular references, a parser without proper safeguards can enter an infinite expansion loop. For example:
<!DOCTYPE root [<!ENTITY a "1234567890"> <!ENTITY a "&a;&a;&a;&a;&a;">]>
Each expansion multiplies the content size, potentially causing the parser to consume gigabytes of memory or hours of CPU time processing a relatively small XML document.
CWE-776 in API Contexts
APIs frequently process XML input for various purposes: configuration files, SOAP messages, data exchange formats, or document uploads. When APIs accept XML without proper validation, they become vulnerable to XML Entity Expansion attacks.
Common API scenarios include:
- SOAP APIs that process XML payloads without entity expansion limits
- File upload endpoints accepting XML documents for processing
- Configuration APIs that parse XML-based configuration files
- Webhooks that receive XML data from external services
- Document processing APIs that handle XML Office formats or similar
The impact on APIs is particularly severe because XML processing often occurs server-side during request handling. A successful attack can exhaust server resources, causing legitimate API requests to fail or the entire service to become unresponsive.
Consider an API endpoint that processes XML resumes:
app.post('/api/resume', (req, res) => {
const xml = req.body.xml;
const parser = new DOMParser();
const doc = parser.parseFromString(xml, 'application/xml');
// Process resume data...
});Without entity expansion protection, this endpoint could be exploited with a malicious XML document designed to trigger exponential expansion.
Detection
Detecting CWE-776 requires testing XML parsers for proper entity expansion limits. Manual testing involves crafting XML documents with nested entity references and observing parser behavior. A simple test case:
<!DOCTYPE test [ <!ENTITY a "1234567890"> <!ENTITY b "&a;&a;&a;&a;&a;"> <!ENTITY c "&b;&b;&b;&b;&b;"> ]> <root>&c;</root>
This expands to approximately 10^5 characters. More aggressive tests can create 10^10 or larger expansions.
Automated scanning with middleBrick can detect this weakness by submitting crafted XML payloads to API endpoints and monitoring for excessive resource consumption or timeout responses. The scanner tests for:
- Entity expansion limits (default should be 10 or fewer levels)
- Maximum entity expansion size (typically 10KB)
- General entity resolution restrictions
- External entity resolution (related CWE-611)
middleBrick's black-box scanning approach sends test XML documents to your API endpoints and analyzes the response patterns. If an endpoint takes unusually long to respond or returns timeout errors when processing specific XML inputs, it indicates potential entity expansion vulnerabilities.
The scanner also checks for proper configuration of XML parser libraries. Many modern XML parsers provide configuration options to disable entity expansion or set strict limits:
// Vulnerable: default parser settings
const parser = new DOMParser();
// Secure: with entity expansion limits
const parser = new DOMParser({
entityExpansionLimit: 10,
maxEntitySize: 10240
});Remediation
Fixing CWE-776 requires both configuration changes and input validation. The primary approach is configuring XML parsers to disable entity expansion or enforce strict limits.
For JavaScript/Node.js applications using DOMParser:
const { DOMParser, XMLSerializer } = require('xmldom');
function createSecureParser() {
return new DOMParser({
locator: {},
errorHandler: (error) => {
throw new Error('XML parsing error: ' + error);
},
// Critical: disable entity expansion
domConfig: {
validate: false,
ignoreUnknownCharacterDenormalization: true,
// Most modern libraries don't expose entity limits directly
// Instead, use a parser that enforces limits
}
});
}
// Alternative: use a parser with explicit limits
const fastXmlParser = require('fast-xml-parser');
function parseXmlSecure(xmlString) {
const options = {
ignoreAttributes: false,
attributeNamePrefix: '',
// Disable entity expansion by not supporting DTDs
ignoreDeclaration: true,
ignoreDoctype: true,
parseTrueNumberOnly: true,
// Set maximum depth to prevent recursion
maxDepth: 10
};
return fastXmlParser.parse(xmlString, options);
}For Java applications using SAXParser:
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
public class SecureXmlParser {
public static SAXParserFactory createSecureFactory() {
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(false);
factory.setXIncludeAware(false);
// Most importantly: disable external entities
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
// Set entity expansion limits if supported
// Some parsers allow setting these via properties
return factory;
}
}For Python applications using ElementTree:
import xml.etree.ElementTree as ET
from defusedxml.ElementTree import parse
# Use defusedxml library which is hardened against XML attacks
def parse_xml_secure(xml_data):
try:
# This parser is safe by default - no entity expansion
tree = parse(xml_data)
return tree.getroot()
except ET.ParseError as e:
raise ValueError(f"XML parsing failed: {e}")Additional defensive measures:
- Input Validation: Validate XML structure before parsing, reject documents with DOCTYPE declarations when not needed
- Timeout Configuration: Implement request timeouts to limit resource consumption during parsing
- Resource Limits: Use container-level resource limits (memory, CPU) for API processes
- Monitoring: Monitor for unusual CPU or memory spikes that might indicate exploitation attempts
Consider using libraries specifically designed to be secure against XML attacks, such as defusedxml for Python or jackson-dataformat-xml with appropriate configuration for Java.