Defensive audit tools for CVE-2026-23918 (Apache HTTPD HTTP/2 double-free RCE) and four related CVEs disclosed in the May 4, 2026 Apache Software Foundation security advisory.
| CVE | Severity | Component | Impact | Affected |
|---|---|---|---|---|
| CVE-2026-23918 | High (CVSS 8.8) | HTTP/2 | Double Free / RCE | 2.4.66 only |
| CVE-2026-24072 | Moderate | mod_rewrite (ap_expr) |
Privilege Escalation | ≤ 2.4.66 |
| CVE-2026-28780 | Low | mod_proxy_ajp |
Heap Buffer Overflow | ≤ 2.4.66 |
| CVE-2026-29168 | Low | mod_md (OCSP) |
Resource Exhaustion | 2.4.30 – 2.4.66 |
| CVE-2026-29169 | Low | mod_dav_lock |
NULL Ptr Deref / DoS | ≤ 2.4.66 |
All issues are patched in Apache HTTP Server 2.4.67.
These tools are intended for use only against systems you own or have explicit written authorization to test. Unauthorized scanning may be illegal in your jurisdiction.
The toolkit is defensive by design:
- No vulnerability payloads, no exploit attempts, no intrusive probing.
- The passive scanner reads only the standard
Server:HTTP header and uses standard TLS ALPN — the same mechanism every modern browser uses to negotiate HTTP/2. - The local auditor is read-only; no file or configuration is modified.
.
├── apache_passive_audit.py # External asset audit (banner-grab + ALPN)
├── apache_local_audit.py # On-host / SSH local audit
├── LICENSE # MIT
├── .gitignore
└── README.md
- Python 3.6+ — works on Ubuntu 18.04's default
python3and every later release. - Standard library only — no external dependencies.
git clone https://github.com/sibersan/cve-2026-23918.git
cd cve-2026-23918
chmod +x apache_passive_audit.py apache_local_audit.pyReads the HTTP Server: header to detect the Apache version and matches it against the CVE table. Additionally, for HTTPS targets, performs a standard TLS ALPN negotiation to determine whether HTTP/2 is exposed — this is the key precondition for CVE-2026-23918 to be exploitable. No exploit payloads are sent.
The script offers h2 and http/1.1 in the TLS handshake's ALPN extension (RFC 7301). The server's choice is the standard, unambiguous answer to "is HTTP/2 enabled?" — used by every modern browser and curl. It does not trigger the vulnerability or any unusual behavior.
The risk verdict reflects this:
- Version 2.4.66 + HTTP/2 confirmed via ALPN → VULNERABLE (RCE vector open)
- Version 2.4.66 + HTTP/2 not negotiated → AT_RISK (still unpatched; other low/moderate CVEs apply, but the High-severity RCE vector is closed)
- ALPN test could not be performed → conservative; assume exposed
- Version ≥ 2.4.67 → SAFE
# Single target
python3 apache_passive_audit.py -t https://web.example.com
# Multiple targets
python3 apache_passive_audit.py -t https://a.example.com -t https://b.example.com
# Targets file, parallel, CSV + JSON output
python3 apache_passive_audit.py -f targets.txt -w 20 -o report.csv --json report.json
# CI / log-friendly (no colors)
python3 apache_passive_audit.py -f targets.txt --no-colortargets.txt format (one target per line, # for comments):
https://www.example.com
intranet.example.local:8443
# old staging box
http://10.0.5.12
| Flag | Description |
|---|---|
-t, --target |
Single target (may be repeated) |
-f, --file |
Targets list file |
-o, --csv |
CSV report output |
--json |
JSON report output |
--timeout |
Request timeout in seconds (default 10) |
-w, --workers |
Parallel worker threads (default 10) |
--no-color |
Disable colored output |
| Code | Meaning |
|---|---|
| 0 | All targets safe |
| 1 | At least one target UNKNOWN or ERROR |
| 2 | At least one target VULNERABLE or AT_RISK |
| Level | Meaning |
|---|---|
VULNERABLE |
Version matches an advisory CVE range AND its precondition is met (e.g. HTTP/2 enabled) |
AT_RISK |
Unpatched version but the High-severity precondition is NOT met; other CVEs still apply |
SAFE |
Version ≥ 2.4.67 |
UNKNOWN |
Banner hidden (ServerTokens Prod) or masked by reverse proxy/WAF — verify with the local audit script |
NOT_APACHE |
Not Apache (nginx, IIS, etc.) |
ERROR |
Connection error |
- Servers with
ServerTokens ProdorMinimalhide the version — the script honestly returnsUNKNOWN. Use the local audit to confirm. - An Apache instance behind a reverse proxy (Cloudflare, F5, nginx, etc.) may not expose its version at the edge.
- ALPN HTTP/2 detection is meaningful only for HTTPS targets. HTTP/2 cleartext (h2c) is rare in practice and not tested.
Runs on the target host (or via SSH) and inspects the Apache binary, version, loaded modules, and HTTP/2 configuration. It also evaluates exploitability preconditions: e.g. if the version is 2.4.66 but HTTP/2 is disabled, the risk for CVE-2026-23918 is downgraded accordingly.
sudo python3 apache_local_audit.py
# JSON report (for centralized inventory)
sudo python3 apache_local_audit.py --json /var/log/apache_audit_$(hostname).json
# Custom binary path
sudo python3 apache_local_audit.py --binary /opt/apache/bin/httpdhttpd -v/apache2 -v— versionhttpd -V— build info,HTTPD_ROOT,SERVER_CONFIG_FILEapache2ctl -Morhttpd -M— loaded modulesdpkg-query/rpm -q— package version- Main configuration plus all files pulled in via
Include/IncludeOptional(including Debian'ssites-enabled/,mods-enabled/) →Protocolsdirective (h2 / h2c / http/1.1)
| Flag | Description |
|---|---|
--binary |
Apache binary path (override auto-detect) |
--json |
JSON report output |
--no-color |
Disable colored output |
| Code | Meaning |
|---|---|
| 0 | SAFE |
| 1 | PATCH_NEEDED or UNKNOWN |
| 2 | VULNERABLE or AT_RISK |
| Level | Meaning |
|---|---|
VULNERABLE |
Unpatched version + High-severity CVE preconditions met (e.g. HTTP/2 enabled) |
AT_RISK |
Unpatched version + at least one CVE precondition met |
PATCH_NEEDED |
Unpatched version but no relevant module/protocol enabled — patch anyway |
SAFE |
Version ≥ 2.4.67 |
UNKNOWN |
Version could not be detected |
sudo/root is recommended for full configuration reads. Without it, some files in sites-enabled/, mods-enabled/, or /etc/httpd/conf.d/ may be unreadable.
To run the local audit on multiple hosts and collect reports centrally, an Ansible ad-hoc example:
ansible all -i inventory.ini -b -m script \
-a "apache_local_audit.py --json /tmp/apache_audit.json --no-color"
ansible all -i inventory.ini -b -m fetch \
-a "src=/tmp/apache_audit.json dest=./reports/ flat=no"Collected JSON files can be merged with jq or a small Python script.
For CVE-2026-23918 (until patched):
- Upgrade Apache HTTP Server to 2.4.67 or later — the only permanent fix.
- As an interim measure, disable HTTP/2: remove
h2andh2cfrom theProtocolsdirective in your configuration, orsudo a2dismod http2on Debian/Ubuntu, then reload the service. - Unload
mod_dav_lockif not in use (CVE-2026-29169). - Audit users / virtual hosts with
.htaccesswrite access (CVE-2026-24072).
Official advisory: https://httpd.apache.org/security/vulnerabilities_24.html
Pull requests are welcome. When adding a new CVE, please:
- Add an entry to
CVE_TABLEwith the affected version range andmatchlambda. - For the local script, define the appropriate
needsfield for precondition checks (loaded module, enabled protocol, etc.). - Update the README table.
- Maintain Python 3.6 compatibility: avoid f-strings,
from __future__ import annotations, PEP 585 generics (list[int]),subprocess.run(capture_output=True), and@dataclass.
MIT © 2026 SiberSAN
This software is provided "as is", without warranty of any kind. Validate in a test environment before production use. The user assumes all legal responsibility for any use against unauthorized systems.