Blog · E.13 · Technical

XXE injection explained

Hand an XML parser a booby-trapped document and, if it's configured the old default way, it will happily fetch a file off the server's disk or fire a request at an internal system on the attacker's behalf. That's XXE — XML External Entity injection — and it hides in more places than people realise: SOAP, SAML, and every DOCX, XLSX or SVG upload. Here's how it works, what it does, where it lurks, and how to kill it at the root.

XXEXMLSSRFFile DisclosureWeb AppSec
XXE: External Entity Resolution · File Disclosure · SSRF · Denial of Service · Hides in SOAP / SAML / DOCX / SVG · Fix = Disable DTDs & External Entities XXE: External Entity Resolution · File Disclosure · SSRF · Denial of Service · Hides in SOAP / SAML / DOCX / SVG · Fix = Disable DTDs & External Entities
// TL;DR

XXE (XML External Entity) injection occurs when an app parses attacker-supplied XML with a parser that resolves external entities. The attacker defines a malicious entity and the parser fetches whatever it points to, enabling local file disclosure (config, credentials, keys), SSRF (reaching internal services and cloud metadata), and denial of service (billion-laughs). It hides wherever XML is accepted — SOAP, XML APIs, SAML, and DOCX/XLSX/SVG uploads (all XML under the hood). Blind variants exfiltrate out-of-band. The definitive fix: disable external entities and DTD processing in the parser — simple and complete, unlike filtering. Full explainer below; XXE is part of every web app test we run.

// 01 How XXE works

XML has a feature called entities — placeholders that expand to some value when the document is parsed. Most are harmless, but XML also supports external entities, which tell the parser to fetch content from a URI (a file path, a URL) and substitute it in. The vulnerability is simple: if an application parses user-supplied XML with a parser that resolves external entities (historically the default in many libraries), an attacker can define an external entity pointing at, say, file:///etc/passwd or an internal URL, and the parser dutifully retrieves it and includes the content in the parsed output. The attacker never needs code execution — they just abuse a legitimate XML feature that should have been turned off. That gap between “XML feature” and “attacker capability” is the whole vulnerability.

// 02 What an attacker can do

01

File disclosure

Read sensitive files — config, credentials, private keys, source — off the server's filesystem.

02

SSRF

Make the server request internal services or cloud metadata — a stepping stone to deeper compromise.

03

Denial of service

Entity-expansion (billion-laughs) attacks that exhaust server memory.

04

Out-of-band exfil

In blind cases, exfiltrate data to an attacker-controlled server.

The two that matter most in practice are file disclosure and SSRF. File disclosure hands the attacker your secrets; SSRF turns your server into a launch point against your internal network and cloud — which is why XXE so often chains into a much larger compromise rather than staying a “read one file” bug.

// 03 Blind XXE & out-of-band exfiltration

The straightforward case returns the fetched content in the app's response, so the attacker sees the file. But mature apps often don't echo parsed XML back — that's blind XXE, and it's where weaker tests give up. Skilled attackers (and testers) don't. Using out-of-band techniques, they make the parser send the extracted data to an attacker-controlled server — embedding the file's contents in a URL the server is tricked into requesting, or using external DTDs to stage a two-step exfiltration. The impact is identical to the visible case; only the detection is harder. This is precisely the kind of finding a scanner misses and a human finds, because confirming blind XXE requires setting up a listener and reasoning about the parser's behaviour rather than matching a signature.

// 04 Where XXE hides in modern apps

“We don't use XML” is the sentence that precedes many XXE findings, because XML is lurking where you don't see it. The obvious spots are SOAP web services and XML API endpoints. The non-obvious ones cause the real damage: SAML single sign-on is XML-based, so authentication flows can be vulnerable; and a huge range of file formats are XML under the hoodDOCX, XLSX, PPTX, SVG and others are zipped XML. So a feature as innocent as “upload your profile picture” (accepting SVG) or “import a spreadsheet” (XLSX) can be an XXE entry point. A thorough test probes every place XML could be parsed, especially document and image upload flows — the ones most teams never think to check, and which tie into broader input-handling risks.

// 05 How to test and fix it

Testing: at each XML entry point, submit a payload defining an external entity pointing to a local file or an attacker-controlled URL, and observe whether the parser resolves it — directly in the response, or out-of-band via a listener for blind cases. Include the sneaky vectors: SAML, and SVG/DOCX/XLSX uploads. Fixing: the definitive remedy is to disable external entity and DTD processing in the parser — this removes the vulnerability at the root, and it's what OWASP recommends. Every language and XML library has specific flags to turn off DTDs and external entities; set them everywhere XML is parsed. Where XML isn't actually needed, prefer JSON. Input filtering and WAFs help at the margins but are not a substitute: the safe parser configuration is simple and complete, while filtering is easy to bypass. Every web app engagement we run tests for XXE across all these vectors, per our methodology.

// 06 Frequently asked questions

What is XXE injection?

A vulnerability that arises when an app parses XML input with a parser configured to resolve external entities. An attacker embeds a malicious external entity in the XML, and the parser fetches and includes what it points to — enabling local file reads, server-side request forgery, and sometimes denial of service. It exists because many XML parsers historically resolved external entities by default.

What can an attacker do with XXE?

Local file disclosure (config, credentials, keys), SSRF (making the server request internal services or cloud metadata, leading to further compromise), and denial of service (billion-laughs entity expansion). In blind variants, attackers use out-of-band techniques to exfiltrate data. Impact ranges from information disclosure to a foothold for deeper attacks.

Where does XXE hide?

Anywhere XML is accepted — SOAP and XML APIs, SAML authentication (XML-based), and file uploads for formats that are XML under the hood like DOCX, XLSX, SVG and PPTX. Because these aren't obviously XML, XXE is often missed. A tester probes every XML entry point, including document and image upload flows.

How do you prevent XXE?

Disable external entity and DTD processing in the XML parser entirely — this removes it at the root and is OWASP's recommendation. Each language/parser has specific settings. Where XML isn't needed, prefer JSON. Input validation and WAFs help but aren't a substitute, because the safe configuration is simple and complete while filtering is easy to bypass.

// 07 Related reading

UG

Usama Gul

Founder & Penetration Testing Lead, CyberFortify

Hunts XXE across every XML entry point — SOAP, SAML and the DOCX/SVG uploads teams forget — including the blind, out-of-band variants scanners never confirm.

Parsing XML anywhere?

SOAP, SAML, or file uploads — if your app touches XML, it can be XXE-vulnerable. We probe every entry point, including the blind cases, and hand you the exact parser fix.

Scope a web app test → Web app testing →