Skip to content
العربية

XXE (XML External Entities)

How an XML parser that resolves external entities lets an attacker read server files and reach internal services, and why disabling entities is the only real fix.

Estimated time
25 min
Level
Intermediate
Your progress in this track0%

XML can define entities — named stand-ins for text, like &. It also allows external entities, whose value is loaded from a URL the document names. If a server parses attacker-supplied XML with external entities enabled, the attacker defines an entity pointing at a server file or an internal URL, and the parser fetches it and drops the content into the document.

What is the vulnerability?

malicious.xml
<!DOCTYPE r [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<r>&xxe;</r>

The <!ENTITY ... SYSTEM "url"> defines an external entity; &xxe; references it. A vulnerable parser resolves file:///etc/passwd and the document becomes <r>root:x:0:0:...</r>. The import feature just read a server file for you.

Why does it happen?

External entities are an old XML feature, on by default in many parsers, that almost no application actually needs. When the parser trusts the document to tell it what to load, attacker XML tells it to load secrets.

Beyond reading files

  • Keyword blacklist. Ban SYSTEM and PUBLIC still defines an external entity by URL. A blacklist of keywords is incomplete — you bypass it in the medium lab.
  • XXE becomes SSRF. Block file:// and an http:// entity still reaches the network, turning XXE into Server-side request forgery: the server fetches a URL you choose, reaching internal services it can see and you cannot. — the server fetches internal URLs, including the cloud metadata service. You do exactly that in the hard lab.

How to prevent it

safe.js
// Disable DTDs and external entities entirely (option names vary by library).
const parser = new XMLParser({ resolveExternalEntities: false, processEntities: false });
parser.parse(xml);
// Or simply accept JSON, which has no entities at all.

Turn off DTD processing and external entity resolution in the parser — do not try to filter keywords or protocols, because there is always another one. If you do not need XML, use JSON. Also isolate the service at the network level so that even an SSRF via XXE reaches nothing sensitive.

Review questionA server blocks any XML containing 'SYSTEM' to stop XXE. Is that enough?

Labs

  • An external entity reads a file

    EasyBrowser lab

    Define an external entity that reads /etc/passwd and make the document render its content.

  • It bans one keyword

    MediumBrowser lab

    Read /etc/passwd again, bypassing the SYSTEM ban.

  • An entity that reaches the network

    HardBrowser lab

    Use an external XML entity over http to reach the cloud metadata service and steal the access keys.