Skip to main content
EPSS 0.3%top 85%

CVE-2026-75834: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') in getgrav grav

0
Medium
Published: 09/17/2026 (09/17/2026, 20:44:39 UTC)
Source: CVE Database V5
Vendor/Project: getgrav
Product: grav

Description

## Vulnerability Details **Component**: getgrav/grav core **File**: `system/src/Grav/Common/Security.php` **Function**: `detectXss()` (all six entries in the `$patterns` array use the PCRE `u` modifier), invoked from `Grav\Common\Data\Validation::checkSafety()` (the save-time XSS gate for any non-`security.xss_whitelist` account's blueprint field, including the page `content` field) and `detectXssInEditorContent()` (the render-time backstop for GHSA-2c4f-86xc-cr74) **CWE**: CWE-79 (Stored XSS), root-caused by CWE-20 (Improper Input Validation — fails open on malformed input) **Severity**: High **CVSS**: 8.0 — CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N ### Relationship to prior advisories This project's `detectXss()`/`checkSafety()` stack has been patched at least three times for the "page editor without super-admin rights stores an event handler that runs for site visitors" bug class: GHSA-9695-8fr9-hw5q / GHSA-c2q3-p4jr-c55f / GHSA-w8cg-7jcj-4vv2 (unquoted-attribute bypasses), GHSA-269c-h76q-8cxw (quoted-attribute-boundary bypass), GHSA-2c4f-86xc-cr74 (render-time Twig-assembled bypass). All three patched the **regex logic**. This is a different, lower-level defect: the PHP regex *engine* silently refuses to evaluate the pattern at all once the input contains one invalid UTF-8 byte, independent of what the regex logic says — no amount of regex-logic hardening fixes this. ### Root Cause Every pattern in `$patterns` uses the PCRE `u` (UTF-8) modifier. PHP's documented behavior: if the subject string contains even one byte sequence that is not valid UTF-8, `preg_match()` does not "skip" that byte or report "no match" — it returns `false` for the **entire call**, with `preg_last_error() === PREG_BAD_UTF8_ERROR`. `detectXss()` only checks truthiness (`if (preg_match(...) || preg_match(...))`), so `false` and "0 matches" are indistinguishable to the calling code. A single stray byte anywhere in a field's value — not even near the actual payload — makes every one of the six checks silently report "no XSS found". Meanwhile, a real browser decoding the same bytes as UTF-8 (the encoding Grav serves pages as) does not fail open: it substitutes the invalid byte with one U+FFFD replacement character and renders the surrounding markup completely normally. The `<img ... onerror=...>` tag is untouched structurally; the payload still fires. ### Vulnerable Code ```php $patterns = [ 'on_events' => '#<(?:"[^"]*"|\'[^\']*\'|[^>"\'])*?(?:[\s\x00-\x20\"\'\/]|"[^"]*"|\'[^\']*\')on\s*[a-z]+\s*=#iu', // ... five more, all with the /u modifier ]; foreach ($patterns as $name => $regex) { if (!empty($enabled_rules[$name])) { if (preg_match($regex, (string) $string) || preg_match($regex, $orig)) { return $name; } // ... } } return null; // reached even when the string contains <img onerror=...>, // as long as it also contains one invalid UTF-8 byte anywhere ``` Directly reproducible against the exact regex: ```php $regex = '#<(?:"[^"]*"|\'[^\']*\'|[^>"\'])*?(?:[\s\x00-\x20\"\'\/]|"[^"]*"|\'[^\']*\')on\s*[a-z]+\s*=#iu'; var_dump(preg_match($regex, "<img src=x onerror=alert(1)>")); // int(1) -- caught var_dump(preg_match($regex, "<img src=x \x80onerror=alert(1)>")); // bool(false), preg_last_error()==4 ``` ### Attack Scenario 1. Attacker holds a page-edit ("publisher") account without super-admin rights. 2. Sets page content to `Hello world \x80<img src=x onerror=alert(document.cookie)>` (a raw invalid UTF-8 byte, deliverable via any non-JSON submission path — e.g. the bundled Form plugin's multipart/urlencoded field, or any blueprint-validated field populated from a raw POST body — `$_POST` values are not UTF-8-validated by PHP). 3. `Validation::checkSafety()` runs `detectXss()` on the value; every `preg_match()` call returns `false`, so `detectXss()` returns `null` ("no violation"). The payload saves unmodified. 4. Any visitor (including a super-admin browsing the public site) loads the page; the browser renders the intact `<img onerror=...>` element, executing the attacker's JavaScript in the visitor's session. ### Impact - **Type**: Stored XSS (CWE-79) - **Auth required**: Page-edit ("publisher") account, not super-admin - **Consequence**: Arbitrary JavaScript execution in any visitor's browser, including a super-admin who views the page — a cross-trust-boundary escalation from publisher to admin-equivalent action capability. ### Recommended Fix ```php public static function detectXss($string, ?array $options = null): ?string { if (null === $string || !is_string($string) || empty($string)) { return null; } // Fail closed: mb_check_encoding() validates the whole string up front // and returns a normal boolean — it never "fails open" the way a // /u-flagged preg_match() does on malformed input. if (!mb_check_encoding($string, 'UTF-8')) { return 'invalid_encoding'; } // ... rest unchanged } ``` `Va

CVSS v4.0

Score 5.1medium

Attack Vector
Network
Attack Complexity
Low
Attack Requirements
None
Privileges Required
Low
User Interaction
Passive
Vuln. Confidentiality
None
Vuln. Integrity
None
Vuln. Availability
None
Subsq. Confidentiality
Low
Subsq. Integrity
Low
Subsq. Availability
None
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N

Affected software

getgrav

grav

Affected versions
>=0 <2.0.14
GitHub Actionsmore threats →ai
getgrav/grav
pkg:github/getgrav/grav
Affected versions
<2.0.14

Run on your own infrastructure? Check whether these packages are installed with threat-finder — our free open-source scanner.

AI-Powered Analysis

Machine-generated threat intelligence

AILast updated: 09/11/2026, 23:18:06 UTC

Technical Analysis

CVE-2026-75834 is a stored XSS vulnerability in Grav CMS prior to version 2.0.14. The issue is in the Security::detectXss() function where all XSS detection patterns use the PCRE /u (UTF-8) modifier. If a single invalid UTF-8 byte is present in the page content, preg_match() returns false for all patterns, bypassing the save-time XSS validation (Validation::checkSafety()). An authenticated attacker with page-edit permissions but without the security.xss_whitelist privilege can inject malicious JavaScript that executes in the browser of any visitor viewing the compromised page.

Potential Impact

An attacker with authenticated page-edit permissions can store malicious JavaScript code that executes in the browsers of visitors to the affected pages, potentially leading to session hijacking, defacement, or other client-side attacks. The vulnerability requires authentication but does not require elevated privileges beyond page editing. The CVSS 4.0 score is 5.1 (medium severity), reflecting the moderate impact and attack complexity.

Mitigation Recommendations

Upgrade Grav to version 2.0.14 or later where this vulnerability is fixed. Since the vulnerability is patched in 2.0.14, applying this official fix fully mitigates the issue. Until patched, restrict page-edit permissions to trusted users and consider additional input validation or content sanitization controls as temporary measures.

Pro Console: star threats, build custom feeds, automate alerts via Slack, email & webhooks.Upgrade to Pro

Technical Details

Data Version
5.2
Assigner Short Name
VulnCheck
Date Reserved
2026-08-18T10:57:39.580Z
Cvss Version
4.0
State
PUBLISHED

Threat ID: 6a844366c6e8be03322294f6

Added to database: 08/18/2026, 11:35:02 UTC

Last enriched: 09/11/2026, 23:18:06 UTC

Last updated: 10/03/2026, 02:46:06 UTC

Views: 59

Community Reviews

0 reviews

Crowdsource mitigation strategies, share intel context, and vote on the most helpful responses. Sign in to add your voice and help keep defenders ahead.

Sort by
Loading community insights…

Want to contribute mitigation steps or threat intel context? Sign in or create an account to join the community discussion.

Actions

PRO

Updates to AI analysis require Pro Console access. Upgrade inside Console → Billing.

Please log in to the Console to use AI analysis features.

Need more coverage?

Upgrade to Pro Console for AI refresh and higher limits.

For incident response and remediation, OffSeq services can help resolve threats faster.

Latest Threats

Breach by OffSeqOFFSEQFRIENDS — 25% OFF

Check if your credentials are on the dark web

Instant breach scanning across billions of leaked records. Free tier available.

Scan now
OffSeq TrainingCredly Certified

Lead Pen Test Professional

Technical5-day eLearningPECB Accredited
View courses