HackproofHacks
Vulnerability walkthrough · XML

How to Exploit XXE: A Step-by-Step Lab Walkthrough

12 min read · Lab: PortSwigger Web Security Academy

In one line

XXE is when an app parses XML you send and you sneak in a special entity that makes the parser go read a file off the server and hand it back to you.

What this is, for a beginner

XML external entity injection targets applications that parse XML. The XML standard allows documents to define entities, including external ones that reference a file or URL, and if the parser resolves those external entities and the application returns the result, an attacker can define an entity that points at a server file and have its contents reflected back.

The most common outcome is reading local files from the server, but XXE can also be used for server-side request forgery, reaching internal systems the same way. The root cause is an XML parser configured to resolve external entities on untrusted input, which most modern parsers can and should disable.

The legal lab we use: PortSwigger Web Security Academy

PortSwigger provides free, legal, hosted XXE labs with isolated targets you are explicitly authorized to attack.

PortSwigger Web Security Academy project page →

Full walkthrough: exploiting it step by step

Step 1 — Open the XXE file-read lab

Start the PortSwigger lab titled Exploiting XXE to retrieve files. It has a feature that submits XML, such as a stock check, which the server parses.

Expected result: A request that sends an XML document to the server and returns a value derived from it.

Step 2 — Capture the XML request in Burp

Proxy through Burp, trigger the feature, and find the request whose body is XML. Note where a value from the XML is echoed in the response, which is where extracted data will appear.

Burp — original XML body
<?xml version="1.0"?>
<stockCheck><productId>1</productId><storeId>1</storeId></stockCheck>

Expected result: The server parses the XML and reflects a value (such as the productId) in the response.

Step 3 — Define an external entity

Send the request to Repeater and add a DOCTYPE that defines an external entity pointing at a server file, then reference that entity where a value is reflected.

Burp Repeater — XXE payload
<?xml version="1.0"?>
<!DOCTYPE stockCheck [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<stockCheck><productId>&xxe;</productId><storeId>1</storeId></stockCheck>

Expected result: The response contains the contents of /etc/passwd where the productId value would normally be, confirming file read via XXE.

Step 4 — Understand the SSRF variant

Swap the file URL for an internal http URL to turn XXE into server-side request forgery, reaching internal services. PortSwigger has a dedicated lab for this next step.

XXE-to-SSRF payload
<!ENTITY xxe SYSTEM "http://169.254.169.254/">

Expected result: The parser fetches the internal URL, showing XXE can pivot to internal systems, not just read files.

Free resource

Get the free 35-week ethical hacking roadmap

The exact order I'd learn this in, every vulnerability and tool, week by week, with the labs to practise each one. Enter your email and I'll send it over, plus one practical lesson each week.

How to detect and fix this

How to detect it

  • Identify any endpoint that accepts XML (or content types that wrap XML, such as some SOAP and document uploads) and test whether it resolves a defined entity.
  • Use a benign external entity pointing at a server you control to detect blind XXE through an out-of-band request, even when nothing is reflected.
  • Review parser configuration in source; a parser with external entity resolution enabled on untrusted input is the smoking gun.

How to fix it

  • Disable external entity and DTD processing in your XML parser; most libraries offer a single setting to turn this off, and that is the definitive fix.
  • Prefer less complex data formats such as JSON where XML is not genuinely required.
  • Keep XML libraries updated and apply secure-by-default parser configurations across the codebase.
  • Validate and constrain uploaded documents, and do not reflect parsed values back without need.

Common beginner mistakes

  • Only testing reflected XXE and missing blind XXE, which needs an out-of-band callback to confirm.
  • Forgetting content types; XML can hide inside SOAP, SVG uploads, and office documents, not just obvious XML bodies.
  • Assuming modern frameworks are immune; misconfigured parsers still appear, so test rather than assume.
  • Testing against systems you do not own instead of the isolated PortSwigger labs.

FAQ

What can XXE actually achieve?

Most commonly, reading arbitrary files from the server. It can also perform server-side request forgery to reach internal systems, and in some configurations contribute to denial of service. The file-read and SSRF outcomes are the ones that matter most in practice.

What is blind XXE?

Blind XXE is when the extracted data is not reflected in the response. You exfiltrate it or confirm the vulnerability using out-of-band techniques, such as making the parser send a request to a server you control, sometimes carrying file contents.

How do I fix XXE properly?

Disable external entity and document type definition processing in the XML parser. Nearly every parser exposes a setting for this, and turning it off closes the vulnerability at its source rather than trying to filter payloads.

Where to go from here

You just exploited one vulnerability in a lab. Here's the structured path.

Scattered tutorials teach you tricks; they don't make you a pentester. My mentorship is 35 weeks of exactly this, every vulnerability and tool in a deliberate order, on real labs, with one-on-one feedback on your work so your mistakes get caught early instead of becoming habits.

Keep practising