Packagist · getgrav/grav
Grav: .htaccess file extension rules bypass via case variation on case-insensitive filesystems
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).
.htaccess rules)webserver-configs/htaccess.txtFile: .htaccess (root of Grav installation)
Reference: webserver-configs/htaccess.txt
# 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.
Install Grav on a system with a case-insensitive filesystem:
./data:/var/www/html)Create or use any plugin that stores sensitive data in its YAML config (e.g., API keys):
user/plugins/my-plugin/my-plugin.yaml
Request the file with a case-varied extension:
GET /user/plugins/my-plugin/my-plugin.YAML HTTP/1.1
Expected: HTTP 403 Forbidden
Actual: HTTP 200 OK — full file contents returned, including any API keys or sensitive configuration
.yaml) containing API keys, credentials, or sensitive settings can be read by unauthenticated users.PHP extension on some configurationsuser/config/system.yaml, user/config/site.yaml, and other system configuration files are accessibleAdd the [NC] flag to the three affected rules:
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.
plugins config subtree from page content, preventing SSTI-based config exfiltrationuser/accounts/, user/config/, and user/data/ folders have separate rules (line 62, 66) that block ALL file types regardless of extension — these are not affectedSisnetic
Is your project exposed to this? Stateward checks every dependency on every pull request and flags it only if your code actually reaches it.
Check my repoSources: CISA KEV (public domain), OSV.dev & GitHub Advisory Database (CC-BY-4.0), FIRST EPSS, NVD/CWE (public domain). Served live from the Stateward advisory database.