XXE: The Complete Practical Guide to XML External Entity Injection
XXE via Content-Type Switch
Turning a JSON endpoint into an XXE: flipping Content-Type to application/xml and rewriting the body as XML with a malicious DOCTYPE.
Published
Not every XXE target advertises XML. Plenty of modern APIs take JSON on the surface but are quietly wired to also parse XML, because the framework negotiates the body format from the Content-Type header. Flip that header, rewrite the body as XML with a malicious DOCTYPE, and you reach an XML parser nobody was guarding. It is one of the most useful tricks for finding XXE where it looks like there is none.
Endpoints that accept JSON but also parse XML
Many frameworks bind the request body based on its declared content type. The route is documented and used as JSON, so that is all the front end ever sends and all anyone tests. But if XML deserialization is also enabled, the same endpoint will happily parse an XML body, and that parser may resolve external entities. The vulnerability was there the whole time, behind a header.
Flipping the Content-Type and rewriting the body
Take a normal JSON request:
POST /api/item HTTP/1.1
Content-Type: application/json
{"name":"widget"}Change the header and rebuild the same object as XML carrying a DOCTYPE:
POST /api/item HTTP/1.1
Content-Type: application/xml
<?xml version="1.0"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<item><name>&xxe;</name></item>If the endpoint parses it, your entity resolves exactly as it would on a native XML API.
Reconstructing the expected object as XML
The server still expects the same logical fields, so your XML has to carry them in a shape it can bind. Mirror the JSON structure as elements: a top-level object element with child elements for each field. Put the entity reference in a field that is either reflected back or, for blind cases, drive the out-of-band technique. Getting the structure close enough that the endpoint accepts the body is half the work.
When a single endpoint speaks multiple formats
Content negotiation means one route can legitimately handle several body formats, and XML is frequently one of them even when it is undocumented. The same trick extends beyond application/xml: some stacks parse text/xml, and some will accept XML inside other wrappers. If the obvious flip does not work, try the alternate XML content types before moving on.
Spotting it from framework behavior
Certain stacks are strong candidates because their default serializers include XML binding, and SOAP-adjacent or older enterprise APIs almost always parse XML somewhere. Watch for tells: an error that mentions an XML or SAX parser, a response that changes shape when you send XML, or documentation that hints at content negotiation. When the framework is known to auto-bind XML, the content-type flip is one of the first things to try.
The content-type switch is how you find XXE on APIs that never looked like XML targets. When you can only inject a fragment and cannot add a DOCTYPE at all, see XInclude attacks. When you want to reach the internal network through the parser, see SSRF via XXE. Practice flipping an endpoint on a free live target.
← Back to XXE: The Complete Practical Guide to XML External Entity Injection