XXE (XML External Entity) injection is a vulnerability where an XML parser is tricked into resolving attacker-defined external entities, letting an attacker read local files, reach internal services, or exfiltrate data — and the hardest variants to spot are blind and out-of-band XXE, where the application returns nothing useful yet the parser still leaks data over the network. If your service accepts XML, SOAP, SVG, DOCX, or any format built on XML, this class applies to you. This guide explains the mechanics conceptually, shows why the out-of-band variants matter, and focuses on detection and prevention rather than weaponized payloads.
What is XXE injection?
XML parsers support a feature called external entities: a document can declare an entity whose value is fetched from a URI. When a parser resolves that URI, it will happily read a local file or make a network request on the attacker's behalf. The illustrative shape of the problem looks like this:
<?xml version="1.0"?>
<!DOCTYPE data [
<!ENTITY ext SYSTEM "file:///etc/hostname">
]>
<data>&ext;</data>
If the parser resolves &ext; and the application reflects the parsed value back, the contents of a local file appear in the response. The root cause is almost never the XML itself — it's a parser configured (usually by default) to resolve external entities and DTDs when it never needed to.
Why blind and out-of-band XXE are the dangerous cases
In a classic XXE, the file contents come straight back in the HTTP response, so it's obvious. The trouble is that many endpoints parse XML but don't echo it — an upload processor, a webhook consumer, a background job. That's where the out-of-band ("OOB") technique comes in, and it's the reason XXE is easy to miss in testing.
In an out-of-band or blind XXE, the attacker points the external entity at a server they control. When the vulnerable parser resolves the entity, it makes an outbound request to that server. No data needs to appear in the application's response at all — the fact that the parser reached out is itself proof of the vulnerability, and carefully constructed parameter entities can smuggle file contents into that outbound request's URL or DNS lookup. This is why a scanner that only inspects HTTP responses will report a clean bill of health on an endpoint that is fully exploitable.
The practical consequences of an unpatched XXE, blind or not, include:
- Reading local files (config, credentials, private keys).
- Server-side request forgery — reaching cloud metadata endpoints or internal-only services the parser can see but the internet can't.
- Denial of service through entity expansion (the "billion laughs" pattern), where nested entities blow up memory.
Where XXE hides beyond obvious XML APIs
Teams that "don't use XML" are often still exposed, because a lot of formats are XML underneath:
- SVG uploads — an SVG is XML, so an image upload feature that renders or processes SVGs can be an XXE sink.
- Office documents — DOCX, XLSX, and PPTX are ZIP archives full of XML parts; a document-ingestion pipeline parses all of them.
- SOAP and legacy APIs — SOAP is XML end to end, and older enterprise integrations lean on it heavily.
- SAML — single sign-on assertions are signed XML, and XXE in a SAML consumer is especially serious given what it protects.
Any place where user-supplied bytes reach an XML parser is in scope, which is a much wider footprint than "the endpoint documented as accepting XML."
How do you prevent XXE injection?
The fix is almost always to disable DTD and external-entity processing in the parser, and it's a per-library configuration. The universal principle: if you don't need DTDs, turn them off entirely — that single setting kills classic, blind, and OOB variants at once.
Java (a frequent XXE source because of its many XML APIs):
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
Python:
# defusedxml hardens the stdlib parsers against XXE and entity expansion
from defusedxml.ElementTree import parse
tree = parse("upload.xml")
.NET, PHP's libxml, Ruby's Nokogiri, and Go's encoding/xml each have an equivalent switch (Go's standard library, notably, does not resolve external entities at all by default). The OWASP XXE Prevention Cheat Sheet documents the exact flags per platform, and it's worth pinning that reference in your team's secure-coding docs.
Beyond parser config:
- Validate uploads by content, and process SVGs and Office documents with libraries configured to reject DTDs.
- Prefer less complex data formats where you control the API — JSON parsers don't have an external-entity feature to abuse.
- Restrict outbound network egress from services that parse XML, so even a successful OOB attempt can't reach an attacker-controlled host or a metadata endpoint.
How do you detect XXE in your code and running apps?
Because the blind variant hides from response inspection, detection needs two angles:
- Static analysis finds XML parser instantiations that don't disable DTDs. This is a reliable SAST pattern — the insecure factory call is a fixed signature — and it catches the vulnerability before it ships.
- Dynamic testing confirms exploitability by using an out-of-band interaction technique: the test payload references a collaborator host, and if that host receives a hit, the endpoint is vulnerable even though the app returned nothing. This is how tools like Burp Suite's Collaborator surface blind XXE that a purely passive scan would miss.
For dependency-level exposure — a vulnerable XML library bundled transitively — a software composition analysis tool maps which of your dependencies parse XML unsafely; an SCA tool such as Safeguard can flag that a transitive XML library carries a known XXE advisory even when your own code never instantiates it directly. Pair SAST for your code, SCA for your dependencies, and OOB dynamic testing for confirmation, and the blind cases stop slipping through.
FAQ
What does the "blind" or "OOB" in blind XXE mean?
It means the application never returns the leaked data in its response. Instead, the vulnerable parser makes an outbound request to a server the attacker controls, and the data is exfiltrated through that channel (or via DNS). "Out-of-band" refers to that separate exfiltration path.
Is XXE only a Java problem?
No, but Java sees it most because its many XML APIs historically shipped with external-entity resolution enabled by default. Any language with a misconfigured XML parser is vulnerable; some, like Go, are safe by default.
Can I be vulnerable to XXE if I don't accept XML?
Yes. SVG images, Office documents (DOCX/XLSX/PPTX), SOAP endpoints, and SAML assertions are all XML under the hood, so features that process them can be XXE sinks even if no endpoint is documented as "XML."
What's the single most effective XXE fix?
Disable DTD processing in your XML parser. If DTDs are off, external entities can't be declared or resolved, which eliminates classic, blind, and out-of-band XXE in one change.