Safeguard
Application Security•

CWE-112 Missing XML Validation: Check Documents Against a Schema

Accepting XML without validating it against a schema or DTD leaves the door open for unexpected input. CWE-112 explained, with a fix.

Safeguard Security Team
3 min read

CWE-112, Missing XML Validation, is a base level weakness with a simple definition: the product accepts XML from an untrusted source but does not validate the XML against the proper schema.

Any service that reads XML from outside its own trust boundary is a candidate: SOAP and other web services, file import features, partner integrations, configuration uploads. MITRE lists it as not language specific.

How it happens

A parser only promises well formed XML, meaning the tags nest and close properly. That is not the same as valid, meaning the document has the structure your code expects. MITRE sums up the risk: most successful attacks begin with a violation of the programmer's assumptions. By accepting an XML document without validating it against a DTD or XML schema, the programmer leaves a door open for attackers to provide unexpected, unreasonable or malicious input.

# Vulnerable: parses and trusts the structure
import xml.etree.ElementTree as ET

def read_order(xml_text):
    root = ET.fromstring(xml_text)
    qty = int(root.find("quantity").text)       # assumes exists and is numeric
    price = root.find("unitPrice").text          # assumes exists
    return qty, price

An attacker can send a missing element, a hundred quantity elements, an enormous text value, or a field in the wrong place. Each one violates an assumption your code made silently.

What an attacker gains

MITRE lists an unexpected state as the consequence, with an impact on integrity. The application does something its author never planned for, because the input did not match the shape the code assumed.

How to find it

MITRE says static analysis (SAST) can find some instances. Manually, find every place that parses XML from a request, upload or message. Check whether a schema or DTD is configured on the parser, or whether the code only reads values it expects.

How to fix it

MITRE's guidance is to always validate XML input against a known XML Schema or DTD. It adds a fair caveat: a parser cannot validate every aspect of a document's content, because it cannot understand the full semantics of the data. But it can do a complete job of checking the document's structure, and so guarantee to the downstream code that the content is well formed and shaped as expected.

So use both layers. Schema validation checks the structure. Your own code then checks business rules, such as whether the quantity is positive.

# Fixed: validate against an XSD first (lxml)
from lxml import etree

schema = etree.XMLSchema(etree.parse("order.xsd"))

def read_order(xml_text):
    doc = etree.fromstring(xml_text.encode())
    if not schema.validate(doc):
        raise ValueError("order does not match schema")
    qty = int(doc.findtext("quantity"))
    if qty < 1 or qty > 1000:
        raise ValueError("quantity out of range")
    return qty, doc.findtext("unitPrice")

Load the schema from a local, trusted file, not from a location named inside the incoming document.

Quick check

Is well formed XML the same as valid XML?

No. Well formed means the syntax is correct. Valid means it conforms to a schema or DTD. CWE-112 is about skipping the second check.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.