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.
- Track
- Web security
- Estimated time
- 25 min
- Level
- Intermediate
Before this lesson
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?
<!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
SYSTEMandPUBLICstill 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 anhttp://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
// 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.
Labs
An external entity reads a file
SolvedEasyBrowser lab
Define an external entity that reads /etc/passwd and make the document render its content.
Enter the labLockedIt bans one keyword
SolvedMediumBrowser lab
Read /etc/passwd again, bypassing the SYSTEM ban.
Enter the labLockedAn entity that reaches the network
SolvedHardBrowser lab
Use an external XML entity over http to reach the cloud metadata service and steal the access keys.
Enter the labLocked
