Executive brief
Grav is a file-based CMS used to build and manage websites. A publisher-level account can inject invalid UTF-8 bytes into page content to bypass the XSS safety checks, allowing malicious JavaScript to be stored and executed in the browsers of all visitors—including administrators—when they view the affected page. This bypasses a critical content validation gate and creates a privilege escalation from publisher to admin-level capability.
Technical details
The vulnerability is a stored XSS (CWE-79) rooted in improper input validation (CWE-20) of the Security::detectXss() function in system/src/Grav/Common/Security.php. All six regex patterns in the function use the PCRE /u (UTF-8) modifier; when preg_match() encounters even a single invalid UTF-8 byte in the input string, it returns false for the entire call rather than evaluating the pattern, causing the XSS detection to silently fail. This happens independently of regex logic and affects all patterns uniformly. An authenticated publisher without super-admin rights can craft page content containing a raw invalid UTF-8 byte followed by an XSS payload (e.g., "\x80<img src=x onerror=alert(1)>"), which bypasses Validation::checkSafety() at save time and stores the payload unmodified. Browsers render the intact payload normally by substituting the invalid byte with a U+FFFD replacement character, allowing the JavaScript to execute in any visitor's session. The recommended fix validates UTF-8 encoding upfront using mb_check_encoding() before regex evaluation.
Affected products
- Grav Grav 2.0.13 and possibly earlier
Timeline
- 2026-09-17: disclosed
- other: CVE-2026-75834 assigned