This article describes an XML External Entity (XXE) injection lab where learners exploit a vulnerable XML parser to read the /etc/passwd file by embedding a malicious DOCTYPE declaration with an external entity reference. It explains how XXE vulnerabilities work, where they occur in real applications, and how to defend against them. Understanding XXE is critical because it remains a widespread vulnerability in systems that accept XML input, particularly in APIs, document formats, and authentication systems.
- How XXE exploits XML entity mechanismsXXE abuses the Document Type Definition (DTD) feature of XML, which allows defining entities that can reference external sources like files or URLs. When an XML parser has external entity loading enabled, it automatically fetches and expands these references. An attacker defines an entity with a file:// URL pointing to /etc/passwd, includes that entity reference in an XML element, and the parser replaces the entity with the file's contents, echoing them back in the output.
- Attack execution requires three stepsFirst, submit valid XML to identify which elements are echoed back in output. Second, add a DOCTYPE declaration that defines an external entity marked SYSTEM with a file:// URL for the target file. Third, place an entity reference (ampersand, entity name, semicolon) inside an echoed element so the expanded file contents appear in the response.
- Root cause is parser misconfigurationThe vulnerability occurs because the XML parser has DTD processing and external entity resolution enabled by default, even though the application never needed these features. The parser follows the XML specification correctly by expanding entity references and fetching external values, but this behavior creates a security gap when handling untrusted input.
- XXE appears in unexpected placesWhile XXE is associated with direct XML uploads, it appears wherever XML is parsed, including SOAP APIs, SAML single sign-on systems, and XML-based file formats like DOCX, XLSX, and SVG. The article notes that attackers may exploit forgotten XML code paths by sending data as XML with modified content-type headers to frameworks that quietly accept both JSON and XML.
- Defense requires explicit parser configurationThe core defense is disabling DTD processing entirely and explicitly disabling external entity resolution in parser settings rather than relying on defaults. Additionally, keeping XML libraries updated is essential because modern versions are safer by default, and using simpler formats like JSON when possible eliminates the attack surface entirely.
- XXE enables multiple attack typesBeyond file reading, XXE can be weaponized for Server-Side Request Forgery (SSRF) attacks where the parser makes requests to attacker-specified URLs. The article also mentions the billion laughs attack, a denial-of-service technique using exponentially-nested XML entities to consume server memory.
- Historical significance and current prevalenceXXE was significant enough to have its own category (A4) in the OWASP Top 10 in 2017 but was folded into Security Misconfiguration in 2021, reflecting that it remains a recognized threat but is now grouped with broader configuration issues. The vulnerability persists across organizations because XML parsing is often overlooked in security reviews.
Bottom line: XXE vulnerabilities result from enabling XML external entity processing by default when it is not needed; defenders must explicitly disable DTD processing and external entity resolution in all XML parsers handling untrusted input, and remember that XXE can hide in APIs, document uploads, and authentication systems beyond obvious XML endpoints. Attackers can leverage this misconfiguration to read arbitrary server files, making it essential to configure parsers securely and prefer simpler formats
📋 In this walkthrough
What this lab teaches
XML External Entity injection (XXE) abuses the document type definition (DTD) part of XML. A DTD can declare an entity whose value comes from an external source such as a file path or URL. If the parser processes external entities, which many older parsers did by default, an attacker can read local files or make the server send requests.
How DocParse handles XML
DocParse parses uploaded XML with external entity loading switched on, then echoes the parsed values back. The lab is solved when the contents of the system password file, /etc/passwd, appear in the output.
The attack approach
- Submit a small valid XML document first and see which element values are echoed back.
- Add a DOCTYPE declaration at the top of the document. This is where entities are defined.
- Declare an external entity whose system identifier is a
file://URL for the target file. - Use that entity inside an element that gets echoed, so its expanded value is shown to you.
Full walkthrough (spoiler)
Stuck after a few attempts? Open the steps below. Solving it yourself first is worth more XP, and more learning.
Show the step-by-step solution
- Start with a simple document that has a root element and a child element such as a name.
- Above the root, add a DOCTYPE that declares one entity, marked SYSTEM, pointing at the file URL for
/etc/passwd. - Put a reference to that entity (an ampersand, its name, then a semicolon) inside the name element.
- Submit. The parser expands the entity by reading the file and places its contents in the echoed output. The lab marks you solved.
Why it works
The parser is doing exactly what the XML specification describes: when it meets an entity reference, it replaces it with the entity’s value, fetching it if the value is external. The application never needed DTDs or external entities, but the parser had them switched on, so it read a local file because the document asked it to.
Where this happens in the real world
XXE had its own category in the OWASP Top 10 in 2017 (A4) and was folded into Security Misconfiguration in 2021. It shows up wherever XML is accepted, often in places people forget: SOAP APIs, SAML single sign-on, and file formats built on XML such as DOCX, XLSX and SVG. Beyond file reading, XXE can be used for SSRF and, with the “billion laughs” trick, for denial of service.
How to defend against it
- Turn off DTD processing entirely if you do not need it, which is almost always.
- Disable external entity resolution explicitly in your parser’s settings; do not rely on defaults.
- Keep XML libraries updated. Modern versions are safer by default, but old code paths are not.
- Prefer simpler formats such as JSON when you control the API.
- Remember XML in disguise: office documents, SVG uploads and SAML responses all need the same care.
Try it, then go further
Reading about it is the easy part. Open the lab, try your own approach before peeking at the spoiler, and see how many attempts it takes.
