HIGH CWE-776 XML Injection

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:

  1. Input Validation: Validate XML structure before parsing, reject documents with DOCTYPE declarations when not needed
  2. Timeout Configuration: Implement request timeouts to limit resource consumption during parsing
  3. Resource Limits: Use container-level resource limits (memory, CPU) for API processes
  4. 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.

Frequently Asked Questions

How does CWE-776 differ from CWE-611 (XML External Entities)?
CWE-776 focuses on internal entity expansion causing resource exhaustion, while CWE-611 involves external entity references that can lead to SSRF, local file access, or other information disclosure. Both are XML injection vulnerabilities but have different attack vectors and impacts. CWE-776 causes DoS through computational complexity, while CWE-611 can result in data exfiltration or remote code execution.
Can JSON APIs be vulnerable to CWE-776?
No, CWE-776 specifically affects XML parsers and entity expansion in DTDs. JSON doesn't support entity references or DTDs. However, JSON APIs might have similar DoS vulnerabilities through other means like deeply nested structures causing stack overflows, or extremely large payloads consuming memory. These are different vulnerabilities with different CWE classifications.