
Trigger-aware web server CVE audit for nginx and Apache. Goes beyond version matching by checking whether the vulnerable code path is actually reachable in your configuration. Classifies findings as Active / Latent / Unverified. Single-file Python 3.5+, no dependencies.
Don't ask if you're vulnerable. Ask if you're exploitable.
A single-file Python tool that audits nginx and Apache against known CVEs by checking both the installed version and whether the vulnerable code path is actually reachable through your configuration.
Most CVE scanners stop at version matching: "nginx 1.18.0 — CVE-2026-42945, HIGH severity, you're vulnerable." But many CVEs require a specific configuration pattern to be exploitable. A scanner that ignores configuration floods you with red alerts that don't reflect real risk — and worse, it can hide the latent risks that would become real if your config changed tomorrow.
web_server_audit answers two distinct questions per CVE:
Combining those yields three honest classifications:
| Classification | Meaning |
|---|
| 🔴 Active exploitation risk | Vulnerable version and trigger present. Exploitable today. |
| 🟡 Latent risk | Vulnerable version, no trigger. Becomes exploitable if config changes introduce the pattern. |
| ⚪ Unverified | Config unreadable; status unknown. |
git clone https://github.com/YOUR_USERNAME/web-server-audit.git
cd web-server-audit
sudo python3 web_server_audit.py
| CVE | Severity | Trigger pattern |
|---|---|---|
| CVE-2026-42945 (Rift) | HIGH | rewrite + unnamed capture ($1,$2) + ? in replacement |
| CVE-2026-42946 | MEDIUM | scgi_pass or uwsgi_pass in use |
| CVE-2026-40701 | MEDIUM | ssl_stapling on + resolver together |
| CVE-2026-42934 | LOW | charset/charset_types/source_charset directives |
The Apache CVE list is currently empty but the structure is in place — see Extending below.
Beyond CVEs, the tool also reports:
/proc/sys/kernel/randomize_va_space) — full ASLR materially reduces RCE exploitability of memory bugsesm-infra and esm-appsnginx, apache2, systemctl, ss, journalctl when available; skips checks gracefully otherwise# Compact report (default — hides OK lines)
sudo python3 web_server_audit.py
# All findings including OK lines
sudo python3 web_server_audit.py --verbose
# No ANSI colors (good for pipes, logs, CI output)
sudo python3 web_server_audit.py --no-color
# Machine-readable JSON
sudo python3 web_server_audit.py --json
| Code | Meaning |
|---|---|
| 0 | No issues |
| 1 | Warnings or non-CVE critical findings only |
| 2 | At least one CVE is actively exploitable |
Exit code 2 is a natural CI/CD failure signal.
========================================================================
Web Server Audit - 2026-05-16T01:24:55
Host: web-prod-01
web_server_audit.py v1.0.0 - SiberSAN - MIT License
========================================================================
[system]
------------------------------------------------------------------------
[OK] OK ASLR fully enabled (randomize_va_space=2)
[i] INFO OS: Ubuntu 18.04.6 LTS
[!] WARN Ubuntu 18.04 is in ESM-only support
[nginx] version 1.18.0 (active)
------------------------------------------------------------------------
[i] INFO nginx listening on: 0.0.0.0:80, 0.0.0.0:443
[i] INFO CVE-2026-42945 (HIGH): version vulnerable but NOT triggered
Trigger: rewrite + unnamed capture ($1,$2) + '?' in replacement
Evidence: No rewrite directives in configuration
[i] INFO CVE-2026-42946 (MEDIUM): version vulnerable but NOT triggered
[!] WARN nginx installed from PPA (1.18.0-3ubuntu1+bionic1)
========================================================================
Real-risk summary
------------------------------------------------------------------------
ACTIVE EXPLOITATION RISK: none detected.
LATENT RISK - vulnerable version, no trigger in config (3):
- [nginx] CVE-2026-42945 (HIGH)
- [nginx] CVE-2026-42946 (MEDIUM)
- [nginx] CVE-2026-42934 (LOW)
These become exploitable if config changes introduce the trigger.
Mitigation: config-change discipline + plan upgrade.
========================================================================
Findings: 0 critical, 2 warnings
========================================================================
Adding a new CVE takes two steps.
1. Write a trigger function that takes the full config text (nginx -T output) and returns (triggered: bool, evidence: str):
def _trigger_my_cve(conf):
hits = [l for l in conf.splitlines() if re.search(r'risky_directive', l)]
if hits:
return True, "Found: " + hits[0]
return False, "Pattern not present"
2. Add the entry to NGINX_CVES (or APACHE_CVES):
{
"id": "CVE-XXXX-NNNNN",
"name": "Descriptive name",
"severity": "HIGH",
"affected": ("1.10.0", "1.25.0"),
"fixed_in": ["1.25.1"],
"trigger_desc": "Human-readable trigger description",
"trigger_fn": _trigger_my_cve,
},
That's it. The framework handles classification, output formatting, JSON, exit codes, and the executive summary automatically.
--verbose to inspect details when in doubt.Pull requests, issues, new CVE detectors, and support for additional web servers (lighttpd, Caddy, HAProxy, etc.) are all welcome.
When proposing a new CVE detector, please include:
Released under the MIT License.
Copyright (c) 2026 SiberSAN