XXE: The Complete Practical Guide to XML External Entity Injection
SSRF via XXE
Turning XXE into SSRF: pointing a SYSTEM entity at an http URL to reach internal services and cloud metadata through the XML parser, and what you can read back.
Published
Point an external entity at a file and it reads a file. Point it at an http URL and the parser makes a network request, from inside the perimeter, with the server's reach. That is SSRF, delivered through the XML parser. XXE-to-SSRF is how a file-disclosure bug becomes a foothold into the internal network and the cloud control plane.
Pointing SYSTEM at http instead of file
The only change from a file read is the scheme of the SYSTEM target:
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/"> ]>
<data>&xxe;</data>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://internal-admin:8080/"> ]>
<data>&xxe;</data>Everything else is the same entity machinery. The parser resolves the entity by making the request, and if the response reflects the entity, the fetched content comes back to you.
Reaching internal services and admin panels
Because the request originates on the server, the parser inherits its network position: loopback, private ranges, and internal hostnames are all reachable. Aim the entity at the things a firewall would never let you hit directly:
http://127.0.0.1/ internal services on the host
http://internal-admin:8080/ an admin panel behind the perimeter
http://169.254.169.254/... the cloud metadata serviceAny internal HTTP service the parser can reach is now in range, and an unauthenticated internal admin panel is a direct win.
Hitting cloud metadata through the parser
The highest-value SSRF target applies here too: the cloud instance metadata service. An entity pointing at the metadata endpoint makes the parser query it from on-box, and the credentials or identity it returns come back in a reflected field or through an out-of-band callback. The same hardening that blunts classic SSRF applies, header-gated metadata (AWS IMDSv2, GCP, Azure) is harder to reach because the XML parser cannot add the required request headers, so a bare entity is often stuck at header-free targets.
What you read back versus what stays blind
How much you get depends on reflection, exactly like file reads:
- Reflected: the fetched response appears in a field you can see, so you read internal content directly.
- Blind: nothing comes back, so you confirm and extract out-of-band, using the hosted-DTD technique from blind XXE to route the result to your listener.
Even blind, the request still fires, which is enough to reach internal services and trigger the metadata fetch.
Chaining into the full SSRF playbook
Once XXE gives you a request primitive from inside the network, the rest is SSRF. Everything in the SSRF guide applies, reaching internal services, scanning ports by timing, filter bypasses, cloud metadata abuse, and protocol tricks. XXE is just the door, and the SSRF playbook is the building behind it.
SSRF via XXE is where a file reader becomes a network foothold. The way to stop all of it is to stop the parser resolving external resources at all, which is preventing XXE. Practice turning an entity into an internal request on a free live target.
← Back to XXE: The Complete Practical Guide to XML External Entity Injection