GHSA-vwg3-w8w3-pc79: Composer/getgrav/grav vulnerability
Summary
The default .htaccess shipped with Grav (and the reference webserver-configs/htaccess.txt) contains security rules that block direct HTTP access to sensitive file types (.yaml, .yml, .php, .json, .twig, etc.) under user/ and system/vendor/ directories. However, these rules lack the [NC] (No Case) flag, making them case-sensitive. On case-insensitive filesystems (Windows/NTFS, macOS/HFS+, or Linux with Docker volumes mounted from Windows/macOS), an attacker can bypass these rules by requesting files with uppercase extensions (e.g., .YAML, .PHP, .JSON).
Affected Versions
- Grav 2.0.1 (latest stable as of June 2026) — confirmed - Grav 1.7.x — likely affected (same .htaccess rules) - All versions shipping the current webserver-configs/htaccess.txt
Affected Component
File: .htaccess (root of Grav installation) Reference: webserver-configs/htaccess.txt
Affected Rules (lines 68, 70, 72)
apache Line 68 — system/vendor file types RewriteRule ^(system|vendor)/(.)\.(txt|xml|md|html|htm|shtml|shtm|json|yaml|yml|php|php2|php3|php4|php5|phar|phtml|pl|py|cgi|twig|sh|bat)$ error [F]
Line 70 — user file types RewriteRule ^(user)/(.)\.(txt|md|json|yaml|yml|php|php2|php3|php4|php5|phar|phtml|pl|py|cgi|twig|sh|bat)$ error [F]
Line 72 — .md files globally RewriteRule \.md$ error [F]
All three rules use [F] without [NC], making the extension match case-sensitive.
Steps to Reproduce
1. Install Grav on a system with a case-insensitive filesystem: - Windows (native WAMP/XAMPP) - macOS (default HFS+) - Docker on Windows/macOS with volume mounts (e.g., ./data:/var/www/html)
2. Create or use any plugin that stores sensitive data in its YAML config (e.g., API keys): user/plugins/my-plugin/my-plugin.yaml
3. Request the file with a case-varied extension: GET /user/plugins/my-plugin/my-plugin.YAML HTTP/1.1
4. Expected: HTTP 403 Forbidden 5. Actual: HTTP 200 OK — full file contents returned, including any API keys or sensitive configuration
Impact
- Information disclosure: Plugin configuration files (.yaml) containing API keys, credentials, or sensitive settings can be read by unauthenticated users - Source code exposure: PHP source files can be downloaded (instead of executed) when requested with .PHP extension on some configurations - Configuration exposure: user/config/system.yaml, user/config/site.yaml, and other system configuration files are accessible
Fix
Add the [NC] flag to the three affected rules:
apache RewriteRule ^(system|vendor)/(.)\.(txt|xml|md|html|htm|shtml|shtm|json|yaml|yml|php|php2|php3|php4|php5|phar|phtml|pl|py|cgi|twig|sh|bat)$ error [F,NC] RewriteRule ^(user)/(.)\.(txt|md|json|yaml|yml|php|php2|php3|php4|php5|phar|phtml|pl|py|cgi|twig|sh|bat)$ error [F,NC] RewriteRule \.md$ error [F,NC]
The [NC] flag makes the extension matching case-insensitive, covering .YAML, .Yaml, .PHP, .Json, etc.
Mitigating Factors
- On native Linux with ext4 filesystem (case-sensitive), the attack does not work because Apache cannot resolve the uppercase filename to the actual file - Grav 2.0's Twig sandbox blocks access to plugins config subtree from page content, preventing SSTI-based config exfiltration - The user/accounts/, user/config/, and user/data/ folders have separate rules (line 62, 66) that block ALL file types regardless of extension — these are not affected
Environment
- Grav: 2.0.1 - PHP: 8.3 - Apache: 2.4 with modrewrite - OS: Docker (php:8.3-apache) with volume mounted from Windows 10 (NTFS) - Tested: June 2026
Reporter
Sisnetic
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
composer/getgrav/gravto a version that resolves this vulnerability.Fixed in 2.0.4 - Configuration
In the Grav root .htaccess (referenced as webserver-configs/htaccess.txt), update the three affected RewriteRules that block sensitive extensions so the rules use case-insensitive matching by adding the [NC] flag. Concretely: change RewriteRule \.md$ error [F] to RewriteRule \.md$ error [F,NC]; change RewriteRule ^(system|vendor)/(.*)\.(txt|xml|md|html|htm|shtml|shtml|json|yaml|yml|php|php2|php3|php4|php5|phar|phtml|pl|py|cgi|twig|sh|bat)$ error [F] to the same RewriteRule with [F,NC]; and change RewriteRule ^(user)/(.*)\.(txt|md|json|yaml|yml|php|php2|php3|php4|php5|phar|phtml|pl|py|cgi|twig|sh|bat)$ error [F] to the same RewriteRule with [F,NC].
Apache (Grav .htaccess in web root) RewriteRule flags for sensitive file extension blocking (add [NC] where only [F] is present) = Include [NC] in addition to [F]
Event History
Frequently Asked Questions
Which deployments are realistically exposed?
Deployments on case-insensitive filesystems are exposed, including Windows/NTFS, macOS/HFS+, and Linux containers using volumes mounted from Windows or macOS. The affected rules are in the Grav installation root .htaccess and the reference webserver-configs/htaccess.txt.
Does a standard Grav configuration require a customization to be affected?
No. The default .htaccess shipped with Grav contains the affected case-sensitive rules. Versions shipping the current webserver-configs/htaccess.txt are also affected.
What does an attacker need to do to bypass the protection?
The attacker must make an HTTP request for a protected file using an uppercase file extension, such as .YAML, .PHP, or .JSON, on a case-insensitive filesystem. The missing [NC] flag causes the extension-blocking rules not to match that request casing.
How can I check whether an installation has the affected rules?
Inspect the root .htaccess and compare the RewriteRule entries protecting files under system/vendor and user. Rules that list protected extensions but do not include the [NC] flag are case-sensitive and affected on a case-insensitive filesystem.