XML injection (XXE) In getgrav/grav
Description
Grav is Vulnerable to XXE via SVG Upload Dear Grav Security Team,
A security vulnerability was discovered in Grav CMS that allows authenticated attackers to read arbitrary files from the server through XML External Entity (XXE) injection.
Vulnerability Summary
Field | Details |
|---|---|
Vulnerability Type | XML External Entity (XXE) Injection |
Severity | High (CVSS 7.5) |
Affected Versions | Grav CMS <= 1.7.x |
Affected Component | SVG file upload/processing |
CWE | CWE-611: Improper Restriction of XML External Entity Reference |
Authentication Required | Yes (Admin panel access) |
Technical Details
Root Cause
The application uses simplexml_load_string() to process uploaded SVG files without disabling external entity loading. This allows attackers to inject XXE payloads that are processed by the XML parser.
Vulnerable Code Pattern
// Current (Vulnerable): $svg = simplexml_load_string($content); // No LIBXML_NOENT flag or entity loader protection
Attack Vector
Attacker authenticates to Grav admin panel
Uploads malicious SVG file via Pages → Media or File Manager plugin
Server parses SVG and processes XXE entities
Arbitrary file contents are exfiltrated
Impact
An authenticated attacker can:
Read sensitive files:
/etc/passwd - System user information
user/accounts/*.yaml - Admin credentials and 2FA secrets
user/config/system.yaml - System configuration
.env files - Environment secrets and API keys
Perform SSRF - Access internal services via external entity URLs
Potential DoS - Billion laughs attack via recursive entity expansion
Proof of Concept
Malicious SVG Payload
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE svg [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"> <text x="10" y="50">&xxe;</text> </svg>
Steps to Reproduce
Login to Grav CMS admin panel
Navigate to Pages → select any page → Media tab
Upload the malicious SVG file
Observe file contents in response/error or stored output
Recommended Fix
Option 1: Add XXE Protection Flags
libxml_use_internal_errors(true); $svg = simplexml_load_string($content, 'SimpleXMLElement', LIBXML_NOENT | LIBXML_DTDLOAD);
Option 2: Use SVG Sanitizer Library (Recommended)
use enshrined\svgSanitize\Sanitizer; $sanitizer = new Sanitizer(); $sanitizer->removeRemoteReferences(true); $cleanSVG = $sanitizer->sanitize($content);
The enshrined/svg-sanitize library properly strips XXE payloads and other malicious SVG content.
Request
Please acknowledge receipt of this report within 5 business days
Please provide an estimated timeline for a security patch
I am happy to assist with testing the fix
I request a CVE be assigned for this vulnerability
If you have a security advisory process, please include me in the credits
Turki Almatrafi.
Maintainer note — fix applied (2026-04-24)
Fixed across two repos:
Grav core on the 2.0 branch (commit 5a12f9be8, ships in 2.0.0-beta.2) — VectorImageMedium::__construct (the code path that reads width/height from an uploaded SVG) now strips <!DOCTYPE> and <!ENTITY> declarations before parsing, and calls simplexml_load_string with LIBXML_NONET | LIBXML_NOERROR | LIBXML_NOWARNING. On PHP < 8 it also calls libxml_disable_entity_loader(true) for the duration of the parse.
rhukster/dom-sanitizer (commit 02d08ec) — the library Grav ships as its SVG sanitizer. loadDocument now applies the same DOCTYPE/ENTITY strip and passes LIBXML_NONET to loadXML/loadHTML.
With both layers in place, the PoC:
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"> <text x="10" y="50">&xxe;</text> </svg>
no longer expands &xxe;, and the parser cannot make outbound filesystem or network requests for external entities/DTDs. Billion-laughs-style entity expansion is also neutralized because the declarations are stripped before libxml ever sees them.
Files:
system/src/Grav/Common/Page/Medium/VectorImageMedium.php.
tests/unit/Grav/Common/Security/SvgXxeSecurityTest.php — XXE neutralization + billion-laughs + plain-SVG regression.
dom-sanitizer: src/DOMSanitizer.php + two new XXE tests in its own suite.
Mitigation
Update Impact
Minimal update. May introduce new vulnerabilities or breaking changes.
Ecosystem | Package | Affected version | Patched versions |
|---|---|---|---|
packagist | getgrav/grav | 2.0.0-beta.2 |
Aliases
References