Exploiting XInclude to Retrieve Files

Table of Contents
| Platform | PortSwigger Web Security Academy |
| Topic | XML external entity (XXE) injection |
| Lab | Exploiting XInclude to retrieve files |
| Difficulty | Practitioner |
| Goal | Read /etc/passwd from the server |
| Tools | Burp Suite (Proxy + Repeater) |
When you don’t control the whole document#
Every other XXE in this series injected a full XML document, so we could add our
own DOCTYPE and declare entities. Here we can’t. The request body is ordinary
form data (productId=1&storeId=1), and the server takes those values and builds
the XML itself before parsing it. We only control a value inside a document
someone else wrote, so there’s no place to put a DOCTYPE, and entity-based XXE is
off the table.
XInclude is the way in. It’s a feature that lets one XML document pull in
content from elsewhere, and crucially it works on a sub-part of a document, no
DOCTYPE required. If the server places our input into its XML and parses the
result with XInclude enabled, we can make it include a local file.
Finding the injection point#
The Check stock feature sends POST /product/stock with productId and
storeId as form parameters (note Content-Type: application/x-www-form-urlencoded,
not XML). That’s the tell: the value is being embedded into XML server-side rather
than sent as XML. Capture the request and send it to Repeater.
Exploitation: an XInclude payload#
Replace the productId value with an XInclude that pulls in /etc/passwd as
text:
productId=<foo xmlns:xi="http://www.w3.org/2001/XInclude"><xi:include parse="text" href="file:///etc/passwd"/></foo>&storeId=1Piece by piece:
<foo xmlns:xi="http://www.w3.org/2001/XInclude">declares the XInclude namespace on a wrapper element, so the parser recognizes thexi:includetag.<xi:include .../>is the include instruction itself.parse="text"tells it to pull the target in as plain text rather than parsing it as XML (so/etc/passwd, which isn’t valid XML, comes through verbatim).href="file:///etc/passwd"is the local file to include.
Send it. The productId is echoed back in the “Invalid product ID” error, and
the error now contains the file:

The app complains about an invalid product ID, but the “ID” it’s echoing is the
contents of /etc/passwd. Arbitrary file-read confirmed, and the lab is solved.
Real-world impact#
The impact is the same as entity-based XXE, arbitrary file-read as the
application user, but XInclude reaches cases a DOCTYPE can’t:
- Hits partial-document sinks — anywhere user input is slotted into a larger server-side XML document (SOAP bodies, back-end service calls), XInclude can read files even though you never control the XML prolog.
- Reads secrets and source —
.envfiles, framework config, database credentials, cloud tokens, and SSH private keys like~/.ssh/id_rsa. - Pivots to SSRF — swap the
file://URL forhttp://and the include fetches a URL instead (see the XXE-to-SSRF lab ).
Only ever against systems you are authorized to test.
Remediation#
- Disable XInclude processing in the XML parser unless the application genuinely needs it. It is off by default in many parsers but explicitly enabled in some setups, turn it off.
- Disable DTDs and external entities too, the same hardening that stops entity-based XXE.
- Keep user input out of server-side XML, or sanitize it so markup characters can’t introduce new elements.
Key takeaways#
- When you only control a value inside a server-generated XML document, you
can’t declare a
DOCTYPE, so reach for XInclude instead of entities. parse="text"is what lets you read non-XML files like/etc/passwdcleanly.- The fix is the same family as any XXE: disable the dangerous parser features (XInclude, DTDs, external entities) you don’t need.
Related posts#
- Exploiting XXE to Retrieve Files — the same goal with a classic external entity, when you control the whole document.
- Exploiting XXE via Image File Upload — reading a file through an uploaded SVG the server renders.
- Exploiting XXE to Perform SSRF — turning file-read into internal requests.
- Full series: PortSwigger: XML External Entity Injection .