Stored XSS via missing XSS safety check in Admin2 Pages API partial validation
Description
Grav 2.0.0-rc.9 with Admin2 2.0.0-rc.14 contains a stored cross-site scripting (XSS) vulnerability in the Admin2 Pages API save flow.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Affected products
3- Range: =2.0.0-rc.14
Patches
Vulnerability mechanics
Root cause
"The partial-field validation path in validateChangedFields() called Validation::validate() but never Validation::checkSafety(), so Security::detectXss() was never enforced before saving page content."
Attack vector
A non-superadmin editor with page editing privileges can send a `PATCH /pages` request containing an XSS payload (e.g., `<img src=x onerror=alert(1)>`) in the page Markdown content. Because the partial-field validation path in `validateChangedFields()` only ran `Validation::validate()` and skipped `Validation::checkSafety()`, the payload was persisted unsanitized. When any user (including an admin) views the affected page, the stored script executes in their browser session.
Affected code
The vulnerability resides in `AbstractApiController.php` within the `validateChangedFields()` method. This method validates partial field updates submitted via the Admin2 API (e.g., `PATCH /pages`, user and config saves) but never called `Validation::checkSafety()`, so `Security::detectXss()` was never enforced before saving. The patch adds the missing XSS safety check to this partial-validation path.
What the fix does
The patch adds a call to `Validation::checkSafety()` inside `validateChangedFields()` in `AbstractApiController.php`, iterating over the result and appending any safety-check errors to the validation error list. This mirrors the behavior of the full blueprint validator (`BlueprintSchema::validate()`) which already runs `checkSafety()` per field. The fix honors `security.xss_whitelist` (admin.super) and per-field `xss_check: false`, so trusted fields are not over-blocked. A regression test in `BlueprintValidationTest.php` confirms that the XSS payload is rejected while benign Markdown and fields opting out of the check still save correctly.
Preconditions
- authAttacker must have a non-superadmin editor account with page editing privileges
- networkAttacker must be able to send PATCH requests to the Admin2 API (e.g., PATCH /pages)
- inputThe payload must be submitted through a field that does not have xss_check set to false
Generated on Jun 19, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
3- github.com/getgrav/grav-plugin-api/commit/b8ca62eddb7dbea92075a78b1c0a507f03d66d4amitrepatch
- fluidattacks.com/es/advisories/luismitrethird-party-advisory
- github.com/getgrav/grav/security/advisories/GHSA-5wc5-7v9g-f7v6mitrevendor-advisory
News mentions
0No linked articles in our index yet.