Sep 18, 2026·4 min read·5 visits
A parser-differential flaw in Grav CMS's detectXss() filter allows authenticated editors to bypass event-handler detection using unpaired quotes in unquoted attribute values, resulting in stored cross-site scripting.
CVE-2026-75828 is a critical stored cross-site scripting (XSS) vulnerability in the getgrav Grav CMS before version 2.0.15. The vulnerability resides in the detectXss() security filter mechanism, where parser-differential mismatches between the regular-expression-based server-side validation and browser HTML5 tokenization allow authenticated editors to bypass event-handler detection and inject arbitrary JavaScript execution vectors.
Grav CMS is a flat-file content management system that processes content via Markdown and HTML rendering. To ensure safety, Grav employs a centralized security class containing a detectXss() method designed to intercept malicious scripts, event handlers, and unauthorized XML namespaces.
The attack surface of Grav CMS includes markdown-enabled input fields, pages, and metadata accessible to authenticated administrative users and editors. In certain configurations, plugins may expose this filter to unauthenticated inputs, widening the risk vector.
The core of the vulnerability is a parser-differential bug classified under CWE-79. The input validation filter relies on regular expressions that fail to accurately predict the state-machine logic used by modern web browsers when encountering malformed HTML.
The root cause lies in how Security::detectXss() tracks quote pairs. The filter uses regex patterns to identify inline event handlers (such as onerror=) while attempting to ignore harmless occurrences of these sequences within valid quoted attribute strings.
In HTML5, a quote character only starts a quoted attribute state if it immediately follows an equals sign (e.g., attr="value"). An unanchored quote inside an unquoted attribute string (such as the double quote in src=x") is parsed by browsers as a literal character rather than a string delimiter. The browser remains in the unquoted attribute state, and subsequent characters like space and onerror= are parsed as new, independent attributes.
In contrast, the PHP regex parser used in detectXss() treats any quote character as the start of an enclosed string literal. Upon encountering the unpaired quote inside src=x", the engine searches for a matching closing quote, consuming the rest of the element, including the real malicious event-handler attribute. Because the handler is matched inside what the regex assumes is a benign string, validation succeeds.
The vulnerable regular expression configuration in system/src/Grav/Common/Security.php used a generic matching sequence for quotes: (?:"[^"]"|'[^']'). This pattern matched quotes globally without checking if they were actually part of an attribute assignment.
Below is the code snippet comparing the vulnerable and patched regex patterns:
// Vulnerable configuration
'on_events' => '#<(?:"[^"]*"|\'[^']*\'|[^>"\'])*?(?:[\s\x00-\x20\"\u0027\/]|"[^"]*"|\'[^']*\')on\s*[a-z]+\s*=#iu',
// Patched configuration in 2.0.15
'on_events' => '#<(?:=\s*"[^"]*"|=\s*\'[^']*\'|[^>])*?(?:[\s\x00-\x20\"\u0027\/]|=\s*"[^"]*"|=\s*\'[^']*\')on\s*[a-z]+\s*=#iu',The updated regex binds the quote character to an assignment pattern (=\s*) before allowing the parser to consume the content as a string literal. If the quote is not preceded by an equals sign, the parser falls back to matching it as an ordinary tag-body character, forcing the scanner to process the subsequent onerror event handler correctly.
An authenticated editor with permissions to modify site markdown files can insert the malformed payload through the administration panel. Once saved, the raw string is written directly to the flat-file database.
The parser divergence can be visualized in the following diagram:
The payload <img src=x" onerror="alert(document.domain)"> cleanly bypasses the regular expression filter while remaining completely syntactically functional in Chromium-based and Firefox browsers, resulting in arbitrary JavaScript execution when the page is viewed.
The impact of stored cross-site scripting in a CMS environment like Grav is significant. An attacker can hijack the sessions of administrative users who visit the compromised pages, leading to complete control over the application.
Session hijacking allows attackers to execute administrative actions, such as adding backdoor accounts, installing malicious plugins, or reading confidential environment configurations.
Given the flat-file nature of Grav, access to the administration panel translates directly to remote code execution (RCE) on the underlying server. Since administrators can write templates or execute PHP files through standard features, XSS represents a gateway to complete host compromise.
Security administrators must update Grav installations to version 2.0.15 immediately. If an automatic update via the administration console is not possible, the command-line package manager can be used.
For legacy installations where upgrading the entire CMS is infeasible, the patches to system/src/Grav/Common/Security.php should be applied manually to anchor all quote validation steps to the = operator.
Temporary protections can be configured on web application firewalls (WAF) to intercept requests containing unquoted attributes containing internal quotes followed by script handles. An example detection signature has been verified for application-level proxies.
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
grav getgrav | < 2.0.15 | 2.0.15 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network |
| CVSS Score | 9.3 (Critical) |
| EPSS Score | 0.00343 |
| Impact | Stored Cross-Site Scripting (XSS) leading to Session Hijacking / RCE |
| Exploit Status | Proof of Concept |
| KEV Status | Not Listed |
The application does not neutralize or incorrectly neutralizes user-controlled input before it is placed in output that is used as a web page.
An unauthenticated directory traversal vulnerability exists in Grav CMS prior to version 2.0.15. Due to an insecure string-based containment check (str_starts_with) in the pre-boot static asset server, attackers can read files in sibling directories sharing a prefix with the configured asset path when plugin-asset-map.php is enabled.
An arbitrary file write and remote code execution vulnerability exists in Grav CMS before version 2.0.15. The vulnerability is caused by using an incomplete denylist validation approach for bare PHP functions in the Blueprint dynamic-data compiler, allowing authenticated users with page-editing or blueprint-configuration privileges to execute arbitrary functions such as error_log.
CVE-2026-75834 is a stored Cross-Site Scripting (XSS) vulnerability in Grav CMS core, caused by a design flaw in its input validation wrapper Security::detectXss(). Regular expressions using the PCRE UTF-8 /u modifier fail-open when encountering invalid UTF-8 sequences or when the PCRE JIT stack limit is exhausted, allowing authenticated users with page-editing privileges to save malicious HTML and scripts.
CVE-2026-75837 is a critical privilege escalation vulnerability affecting the Grav Flat-File Content Management System (CMS) in versions prior to 2.0.14. Due to a missing security guard on the access field within the core Flex group blueprint configuration file (system/blueprints/user/group.yaml), a delegated administrative operator can submit a crafted payload to elevate their permissions to super-administrator, which can then be leveraged to achieve remote code execution.
CVE-2026-76461 is a critical, unauthenticated, remotely exploitable SQL Injection (SQLi) vulnerability in the email parsing engine of Cisco AsyncOS Software for Cisco Secure Email Gateway (SEG). An unauthenticated remote attacker can exploit this vulnerability by transmitting a specially crafted email message containing malicious SQL statements directly through an affected gateway.
CVE-2026-72819 is a high-severity Remote Code Execution (RCE) vulnerability in Grav CMS before version 2.0.13. The vulnerability lies in the validation of dynamic data providers (callbacks) within the Flex Objects plugin settings and blueprints, allowing administrative users to bypass validation checks via array-notation callables. This validation failure enables administrative users to execute arbitrary PHP classes and methods, including the GPM Installer unZip routine, leading to full remote code execution on the server.