GHSA-w8cg-7jcj-4vv2: Grav is Vulnerable to Stored XSS via Tag Injection
SummaryA low-privileged (with the ability to create a page) user can cause XSS with the injection of `svg` element. The XSS can further be escalated to dump the entire system information available under `/admin/config/info` whenever a Super Admin visits the page; which can further be chained with the use of admin-nonce to do a complete server compromise (RCE).DetailsAffected endpoint: `admin/pages/<page>`
Affected code: `system/src/Grav/Common/Security.php`Specifically the line:assumes that the on_events will always begin with either `whitespace, ', "` which can easily be bypassed with a simple payload like:`<img src=x onload=alert('1')>`This XSS Filter practice is broken.Blacklisting every possible scenario that leads to XSS isn't possible.Regex can't parse HTML.It would be better to use an HTMLPurifier.PoCGrav Core + Admin Plugin
Grav Version: `v1.7.49.5 - Admin v1.10.49.1`Create a low-privileged user with only enough permission to login and perform CRUD on Pages.
![User Perms](https://imgur.com/VkhtE9L.png)Login as the low-privileged user and browse to pages:
![Pages](https://imgur.com/4bmmozN.png)Create a post with the following content:The payload base64 is decoded to:whenever a user with enough privilege visits the attacker-controlled page, a request will be made to the `info` endpoint and the response will be sent to attacker beacon/listener.Save
![Post Created](https://imgur.com/o33Erj2.png)Start a `ncat` listener on port `8001`.Now as a Super Admin visit the `/` of Grav `[http://localhost/grav-admin/`](http://localhost/grav-admin/) for me:
![Visiting Grav](https://imgur.com/kjt7uc9.png)We get a response with the `admin-nonce` and the entire system information:ImpactThis is a **Stored Cross-Site Scripting (XSS)** vulnerability exploitable by a low-privileged user, which leads to **exfiltration of the admin session context**, including the **`admin_nonce`**. This nonce can be abused to **bypass CSRF protections** and **authenticate further requests** to sensitive admin endpoints. Given Grav’s support for **scheduled tasks** and extensible plugin architecture, this can be escalated to **Remote Code Execution (RCE)** under favorable conditions.**Affected Component**: Grav Core + Admin Plugin (`v1.7.49.5` / `v1.10.49.1`)  
**Impact**: Full system compromise via RCE chain originating from low-privilege XSS.`CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H`
`Overall CVSS Score: 9.0`
`High Impact`Maintainer note — fix applied (2026-04-24)Fixed in Grav core on the `2.0` branch: commit [`5a12f9be8`](https://github.com/getgrav/grav/commit/5a12f9be8) — will ship in **2.0.0-beta.2**. Two changes in tandem:**Regex bypass** (detection layer) — the `on_events` regex that missed unquoted handlers is tightened; see the companion GHSA-9695-8fr9-hw5q advisory for details.**Missing dangerous tags** — `svg`, `math`, `option`, and `select` have been added to default `security.xss_dangerous_tags` in [`system/config/security.yaml`](https://github.com/getgrav/grav/blob/2.0/system/config/security.yaml). `svg` and `math` allow inline scripting through their XML namespace and event-handler surface; `option`/`select` are the tags attackers use to break out of the admin's select-template context before dropping the payload.Combined with the tightened `on_events` regex, the PoC `<svg>…<script>…</script></svg>` (and the GHSA-c2q3 `</option></select><img src=x onerror=alert(1)>` variant) now trip at least one detector.**Files:**[`system/config/security.yaml`](https://github.com/getgrav/grav/blob/2.0/system/config/security.yaml) — dangerous-tags list extended.[`system/src/Grav/Common/Security.php`](https://github.com/getgrav/grav/blob/2.0/system/src/Grav/Common/Security.php) — regex tightening.[`tests/unit/Grav/Common/Security/DetectXssTest.php`](https://github.com/getgrav/grav/blob/2.0/tests/unit/Grav/Common/Security/DetectXssTest.php).
CVSS v3.1: 8.9