{"schema":"threatline.record/2","record":{"id":"GHSA-9rq7-4cch-f22j","aliases":["GHSA-9rq7-4cch-f22j"],"summary":"Page editor can call arbitrary static methods through a renamed field in a Flex form","details":"## Summary\nA page editor can get a `data-*@` directive in a page-authored Flex form past Grav's allowed-callable check by renaming the field with `replace-name@`. The renamed field is treated as if it came from the trusted blueprint file, so the directive can call any public static method, for example `Folder::delete`, `Folder::move`, `Folder::copy` or `Utils::download`.\n\n## Affected versions\nGrav 2.0.15 through 2.2.1. Earlier releases applied the allowed-callable check to every directive regardless of where it came from, and 1.7 is not affected.\n\n## Details\nSince 2.0.15, directives from file blueprints are trusted and directives from page-authored forms are held to a `Class::method` allowlist. `Blueprint::extend()` decides which incoming fields are untrusted by reading the incoming form as written. The merge that follows honours `replace-name@` by moving the whole field, directive included, to a new key. That key was never marked untrusted, so `Blueprint::init()` gave it the base blueprint's trust and skipped the allowlist. Both Flex form builders (`FlexForm`, `FlexDirectoryForm`) extend a file-defined directory blueprint with a form from page frontmatter, which is the reachable path.\n\n## Impact\nAn account with page-edit permission (`api.pages.write`, or `admin.pages` in the classic admin) can call server-side methods its role does not grant, giving arbitrary directory deletion, file move or overwrite, and file read outside the page tree.\n\n## Patches\nFixed in Grav 2.2.2. `replace-name@` is removed from untrusted blueprint input before it is merged, so a page-authored field always keeps its untrusted provenance.\n\n## Credits\nReported by @manus-use.\n","categories":["Unclassified"],"product":"getgrav/grav","vendor":"","ecosystem":null,"affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/getgrav/grav/security/advisories/GHSA-9rq7-4cch-f22j","source_modified_at":"2026-10-05T00:00:14Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"composer","name":"getgrav/grav"},"range":">= 2.0.15, < 2.2.2"}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/getgrav/grav/security/advisories/GHSA-9rq7-4cch-f22j","source_modified_at":"2026-10-05T00:00:14Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"composer","name":"getgrav/grav"},"version":"2.2.2"}],"cvss":null,"severity":"High","kev":{"listed":false},"epss":{"probability":null,"percentile":null,"score_date":null},"published_at":"2026-10-05T00:00:14Z","modified_at":"2026-10-05T00:00:14Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/getgrav/grav/security/advisories/GHSA-9rq7-4cch-f22j","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-05T00:00:14Z"}],"sources":["GitHub Advisory Database"],"references":[],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":null,"confidence":"unknown","reviewed":false},"change_timestamp":"2026-10-05T00:00:14Z","content_hash":"7d384898a322910e26750a037867b580b5690f12d5a7be233614d073b5ac5abf"}}
