Executive brief
Grav CMS contains a flaw in how it validates whether the Referer HTTP header comes from the same website. The validation uses an incomplete string prefix check that accepts attacker-controlled domains like "example.com.attacker.tld" as valid when checking against "example.com". An attacker can exploit this by tricking a user into clicking a link from an attacker-owned domain to perform actions on the Grav site or potentially redirect the user to attacker-controlled URLs after authentication.
Technical details
The vulnerability is an origin validation bypass in Grav\Common\Uri::referrer() and Grav\Common\Page\Pages::referrerRoute() that use unanchored prefix matching via str_starts_with($referrer, $base) where $base is the site root URL without a trailing slash (e.g., "https://example.com"). Because there is no boundary check after the prefix, a string matching "https://example.com.attacker.tld" or "https://example.com-attacker.tld" is incorrectly accepted as same-origin. The attack requires user interaction (clicking a link or loading a page from attacker's domain). The vulnerable functions return a relative route derived from the attacker-controlled Referer value via string truncation, which could be leveraged for open redirect if the return value feeds an unvalidated redirect target, particularly in post-login flows. The fix involves anchoring the comparison with a trailing slash or parsing URLs as discrete components (scheme, host, port).
Affected products
- Grav CMS 2.0.15 and earlier 2.x versions
Timeline
- 2026-09-17: disclosed: Advisory published as GHSA-9ccq-2jfg-qw33
- 2026-08-03: other: Vulnerability confirmed present in commit c2b46866857a93a0aa7048e7ed707ed3ed45dbc3 (version 2.0.15)