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.