learn/phase-3/p3-w11/lesson 05
Milestone 11 · lesson 5

XML External Entities (XXE): Reading the Server's Files

Hands-on. See how an XML parser that processes DTDs will happily read files and reach internal systems on your behalf.
Lab: The Parsing Doc Viewer

Make the XML viewer resolve an external entity that reads /etc/passwd, then extract the flag from the echoed file.

XXE Challenge Track0/13 solved

6 live labs — file reads, blind exfil, SSRF. Prove it, then earn your certificate.

What you'll learn

  • Explain what XML, a DOCTYPE, a DTD and an entity are, and where they live in a document.
  • Recognise when an app parses XML you control, and what 'external entity' means.
  • Read a local file with a classic XXE payload, and reach internal URLs with SSRF-style entities.
  • Know the fix: disable external entities and DTD processing in the parser, and avoid parsing XML from untrusted users.

XML External Entities (XXE): Reading the Server's Files

SQL injection smuggles code into a query. XSS smuggles code into a page. XXE smuggles code into an XML parser — and makes the server read its own files or reach its own internal network on your behalf.

The XML machinery

An XML document can start with a DOCTYPE, which can contain a DTD (Document Type Definition) that declares shortcuts called entities:

<!DOCTYPE note [
  <!ENTITY greeting "hello">
]>
<note>&greeting;</note>

An entity is just a named value, and &greeting; is its reference. When a parser processes the document, it expands &greeting; into hello. That alone is harmless. The problem starts when an entity can point at something outside the document:

<!DOCTYPE root [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>&xxe;</root>

SYSTEM tells the parser: go fetch the contents of this URL or file. If the parser honors that, &xxe; expands to the entire contents of /etc/passwd — and if the app then echoes the document back to you (a preview, a rendered page, a converted file), you just read the server's files.

Where XXE hides

Anywhere an application parses XML you can influence:

  • An XML viewer or "prettifier" that echoes your document back.
  • File uploads that accept SVG (SVG is XML) — a profile picture is the classic case.
  • Document converters that process .docx (a ZIP of XML), .xls, .xml, or PDF-to-X formats.
  • Config imports, SOAP/XML-RPC APIs, or anything that takes an XML payload.

You're not limited to file://. Point an entity at http://10.0.0.12/export and the server makes that request from its own network position — SSRF. You can read internal services that your own machine can't reach, and the app shows you the response.

Blind XXE: when the response goes quiet

Sometimes the app stops echoing the expansion (a filter, a format that doesn't render it). The file contents never appear in the response. You can still exfiltrate them out-of-band: declare a parameter entity (written %name;) in the DTD that fetches a remote DTD you host, and that remote DTD reads the local file and requests your listener with the contents in the URL. The app never shows you the data — your server logs do.

The fix

The parser should never process DTDs or external entities from untrusted input. Libraries like libxml2 (XML_PARSE_NOENT | XML_PARSE_DTDLOAD off), Python's lxml with resolve_entities=False, Java's DocumentBuilderFactory with setFeature("http://apache.org/xml/features/disallow-doctype-decl", true) — every mainstream parser has an explicit flag, and the default is often too permissive. And the broader lesson: don't parse untrusted XML at all if you can avoid it (prefer JSON, or use a safe parser with DTDs off).

Try it (terminal)

The lab beside this lesson is a document viewer that parses XML you submit:

  1. curl "http://10.10.10.20/xml-viewer" -d @payload.xml with a normal document — note it echoes the parsed XML.
  2. Send a DOCTYPE with an external entity pointing at file:///etc/passwd and the response contains the file — that's XXE.

Why this matters

XXE is a favorite of real engagements because it's usually a single request to go from "a web app" to "files on the server" or "reach into the internal network". It's been at or near the top of the OWASP Top 10 for years. The skill you're building is recognizing "this app parses XML I control" — the moment you see an XML viewer, an SVG upload, or a document converter, XXE is on the checklist.

Check your understanding

4 questions

Type an answer and press Check. Grading is keyword-based and forgiving, so short answers are fine.

  1. 1

    You upload an SVG avatar to a profile page and the server parses it. Why is that worth testing for XXE?

  2. 2

    Write a minimal XML document that reads /etc/passwd via an external entity.

  3. 3

    An app's XML parser lets you declare <!ENTITY x SYSTEM "http://10.0.0.12/export"> and renders &x;. What is this called, and what does it let you do?

  4. 4

    What is the correct fix for XXE?