This is a jammed side lane, not a bridge collapse
CVE-2016-1546 is an availability-only flaw in Apache HTTP Server's early mod_http2 implementation. In vulnerable builds, a client can abuse HTTP/2 flow-control windows so Apache keeps stream worker threads tied up for too long, eventually starving the worker pool. The affected upstream versions are 2.4.17 and 2.4.18 only, and only when mod_http2 is enabled and HTTP/2 is actually exposed with h2 or h2c.
The raw vendor/NVD baseline of 5.9 / MEDIUM is a little generous for enterprise patch triage in 2025. Yes, it is unauthenticated and remote, but the attack surface is sharply narrowed by an old two-version window, an optional module, and an HTTP/2-specific configuration requirement; there is also no confidentiality or integrity impact and no strong evidence of broad in-the-wild abuse. For a 10,000-host estate, this is backlog cleanup unless you still have externally exposed Apache 2.4.17/2.4.18 with HTTP/2 turned on.
4 steps from start to impact.
Find an actually exposed mod_http2 target
mod_http2 loaded and HTTP/2 negotiated on a reachable listener. In practice this means a legacy server that explicitly enabled Protocols h2 or h2c, because the bug lives in the HTTP/2 worker model rather than generic Apache request handling.- Target is Apache HTTP Server 2.4.17 or 2.4.18
mod_http2is loaded- HTTP/2 is enabled and reachable from the attacker
- Affected window is only two upstream releases
mod_http2was optional and relatively new at the time- Banner data alone does not prove
mod_http2is enabled or vulnerable
http2_module loaded plus h2/h2c enabled.Open an HTTP/2 session with a custom client
nghttp2-based tool or a purpose-built script, the attacker establishes one or a small number of HTTP/2 connections and requests a response large enough to keep stream state active. This is not classic volumetric DDoS; it is a protocol-behavior abuse attack.- Attacker can negotiate HTTP/2 to the target
- Attacker can issue crafted stream requests and flow-control updates
- A browser is not enough; the attacker typically needs tooling that can manipulate HTTP/2 flow control precisely
- Front-end proxies or CDNs that terminate HTTP/2 can break the attack path
Pin H2 worker threads with slow window updates
- Requested content is large enough to keep the response active
- Server allocates H2 worker threads per affected stream
- Attack effectiveness depends on response shape and worker pool sizing
- Aggressive upstream timeouts or HTTP/2-aware connection controls can blunt the impact
Starve stream processing and degrade service
- Enough workers are pinned to exhaust or bottleneck stream processing
- Impact is availability-only
- Blast radius is limited to the affected Apache instance or pool behind the listener
The supporting signals.
| In-the-wild status | No KEV listing and I found no authoritative public reporting of active exploitation campaigns tied to this CVE. Current evidence supports a known DoS technique, not a broadly weaponized campaign. |
|---|---|
| Proof-of-concept availability | No mainstream public exploit repo stands out for this exact CVE, but the attack method is well described in the Imperva HTTP/2 research and later academic work like PRETT2. A competent operator could recreate it with nghttp2 or a custom client. |
| EPSS | 0.41505 from the intel you provided. That is high for a CVE scorecard, but here it likely overstates operational urgency because reachability depends on a very specific legacy Apache + mod_http2 + config combination. |
| KEV status | Not listed in CISA's Known Exploited Vulnerabilities Catalog. No KEV add date applies. |
| CVSS vector reality check | CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H is directionally fair on impact: network-reachable, no auth, availability-only. The important real-world discount is that AC:H understates the deployment friction created by the optional HTTP/2 module and narrow version band. |
| Affected versions | Upstream Apache says this affects 2.4.17 and 2.4.18 only, specifically the HTTP/2 support path in mod_http2. |
| Fixed versions | Upstream fixed it in Apache HTTP Server 2.4.20. Debian tracker also records unstable fixed at 2.4.20-1; Ubuntu notes xenial was not affected because HTTP/2 support was disabled there. |
| Exposure and scanning reality | Internet-wide scanners can find Apache and often HTTP/2 support, but they usually cannot prove this exact condition remotely: vulnerable 2.4.17/2.4.18 *and* mod_http2 loaded *and* HTTP/2 exposed *and* not fixed via backport. This is why asset inventory beats external scanning for prioritization. |
| Disclosure timeline | Apache records: reported 2016-02-02, public 2016-04-11, update 2.4.20 released 2016-04-11. NVD/CVE publication is 2016-07-06. |
| Researcher / reporting org | Apache credits Noam Mazor for the report. Imperva later documented the practical Slow Read / Slow GET attack pattern against Apache HTTP/2. |
noisgate verdict.
The decisive factor is reachability friction: the bug only exists on a two-release upstream window and only when the optional mod_http2 module is enabled and exposed. That sharply shrinks the real population versus generic 'Apache remote DoS' framing, while the impact remains availability-only with no evidence of broad live abuse.
Why this verdict
- Downward adjustment: optional feature gate — exploitation requires
mod_http2, not plain Apache. In many real estates, that single prerequisite wipes out most of the nominally affected population. - Downward adjustment: tiny version window — only 2.4.17 and 2.4.18 upstream are affected. This is not a sprawling 'all 2.4.x' bug.
- Downward adjustment: post-fingerprint precision — an attacker must find servers that are old *and* HTTP/2-enabled *and* directly reachable. That is materially narrower than a generic internet-wide web bug.
- Still not IGNORE — if the server is actually exposed, the attack is unauthenticated and remote and can cause real service degradation with modest attacker bandwidth.
Why not higher?
It is not higher because the blast radius is limited to availability, and the exploit chain is gated by a specific legacy configuration rather than normal Apache exposure. No strong primary-source evidence shows broad in-the-wild abuse, and modern estates often terminate HTTP/2 upstream or have long since moved past these releases.
Why not lower?
It is not lower because the attack does not require credentials, user interaction, or prior compromise. If you still run a directly exposed Apache 2.4.17/2.4.18 instance with HTTP/2 enabled, a remote adversary can realistically cause an outage on that node.
What to do — in priority order.
- Disable HTTP/2 on stragglers — If a legacy server cannot be upgraded immediately, remove
h2/h2cfromProtocolsor unloadmod_http2. For a LOW verdict, noisgate assigns no formal SLA here; do it in the next routine web maintenance cycle, and sooner if the host is internet-facing. - Terminate HTTP/2 upstream — Put the service behind a load balancer, CDN, or reverse proxy that terminates HTTP/2 and talks HTTP/1.1 to the old Apache backend. This breaks the vulnerable protocol path without changing application behavior; for LOW, treat this as backlog hygiene rather than an emergency change.
- Tune connection and request timeouts — Shorter keepalive behavior, request timeouts, and HTTP/2-aware limits reduce how long a slow-reader can pin resources. This is a compensating control, not a guaranteed fix, and it should be applied during normal hardening work for any host you cannot retire yet.
- Watch for H2 worker starvation — Instrument Apache status, reverse-proxy metrics, and host monitoring to alert on long-lived HTTP/2 streams with poor throughput and rising busy workers. For a LOW finding, fold this into standard observability improvements instead of spinning up a special response project.
- A generic signature WAF rule is weak here because the traffic can look syntactically valid; the abuse is in HTTP/2 flow-control behavior, not an obvious payload.
- TLS alone does nothing. HTTP/2 over TLS (
h2) is still the vulnerable path. - Just adding more worker threads is not a fix; it only raises the cost for the attacker and can still leave you vulnerable to resource starvation.
Crowdsourced verification payload.
Run this on the target Linux/Unix Apache host as a local auditor. Invoke it with bash check_cve_2016_1546.sh or bash check_cve_2016_1546.sh /usr/sbin/apachectl; it needs only enough privilege to execute apachectl/httpd config inspection commands, not full root in most deployments.
#!/usr/bin/env bash
# check_cve_2016_1546.sh
# Detect likely exposure to CVE-2016-1546 on Apache HTTP Server.
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -u
APACHECTL="${1:-}"
find_apachectl() {
local candidates=(
"$APACHECTL"
/usr/sbin/apachectl
/usr/sbin/httpd
/usr/local/apache2/bin/apachectl
/usr/local/bin/apachectl
apachectl
httpd
)
local c
for c in "${candidates[@]}"; do
[ -n "$c" ] || continue
if command -v "$c" >/dev/null 2>&1; then
command -v "$c"
return 0
elif [ -x "$c" ]; then
echo "$c"
return 0
fi
done
return 1
}
ver_ge() {
# returns 0 if $1 >= $2
[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | tail -n1)" = "$1" ]
}
APACHE_BIN="$(find_apachectl)" || {
echo "UNKNOWN - could not locate apachectl/httpd"
exit 2
}
VSTR="$($APACHE_BIN -v 2>/dev/null | awk -F'Apache/' '/Server version/ {print $2}' | awk '{print $1}')"
if [ -z "$VSTR" ]; then
echo "UNKNOWN - could not determine Apache version via '$APACHE_BIN -v'"
exit 2
fi
MAJMINPATCH="$VSTR"
MODULES="$($APACHE_BIN -M 2>/dev/null || true)"
RUNCFG="$($APACHE_BIN -t -D DUMP_RUN_CFG 2>/dev/null || true)"
FULLCFG="$($APACHE_BIN -t -D DUMP_VHOSTS 2>/dev/null || true)"
HTTP2_LOADED=0
if echo "$MODULES" | grep -Eq '(^|\s)http2_module(\s|$)'; then
HTTP2_LOADED=1
fi
H2_ENABLED=0
if echo "$RUNCFG" | grep -Eiq '\bh2(c)?\b'; then
H2_ENABLED=1
fi
# Fallback: parse common config locations if run_cfg did not expose protocol lines
if [ "$H2_ENABLED" -eq 0 ]; then
for f in /etc/httpd/conf/httpd.conf /etc/apache2/apache2.conf /etc/apache2/sites-enabled/* /usr/local/apache2/conf/httpd.conf; do
[ -r "$f" ] || continue
if grep -Eiq '^[[:space:]]*Protocols[[:space:]].*\bh2(c)?\b' "$f" 2>/dev/null; then
H2_ENABLED=1
break
fi
done
fi
# Known-safe outcomes first
if ! echo "$MAJMINPATCH" | grep -Eq '^2\.4\.(17|18)$'; then
if ver_ge "$MAJMINPATCH" "2.4.20"; then
echo "PATCHED - Apache version $MAJMINPATCH is at or above upstream fix 2.4.20"
exit 0
fi
# Older or vendor-backported builds are ambiguous
if [ "$HTTP2_LOADED" -eq 0 ] || [ "$H2_ENABLED" -eq 0 ]; then
echo "PATCHED - vulnerable HTTP/2 path not active (http2_module loaded=$HTTP2_LOADED, h2 enabled=$H2_ENABLED)"
exit 0
fi
echo "UNKNOWN - Apache version $MAJMINPATCH is not an exact upstream vulnerable version, but runtime/backport status is unclear"
exit 2
fi
# Exact upstream vulnerable versions
if [ "$HTTP2_LOADED" -eq 1 ] && [ "$H2_ENABLED" -eq 1 ]; then
echo "VULNERABLE - Apache $MAJMINPATCH with mod_http2 loaded and HTTP/2 enabled"
exit 1
fi
if [ "$HTTP2_LOADED" -eq 0 ] || [ "$H2_ENABLED" -eq 0 ]; then
echo "PATCHED - Apache $MAJMINPATCH present, but vulnerable path not active (http2_module loaded=$HTTP2_LOADED, h2 enabled=$H2_ENABLED)"
exit 0
fi
echo "UNKNOWN - unable to conclusively determine mod_http2/HTTP2 runtime state"
exit 2
If you remember one thing.
http2_module, disable HTTP/2 on any confirmed stragglers during the next normal change cycle, and retire or upgrade them as routine hygiene; for a LOW verdict, the noisgate mitigation SLA is no SLA (treat as backlog hygiene) and the noisgate remediation SLA is also no SLA (treat as backlog hygiene).Sources
- Apache HTTP Server 2.4 vulnerabilities entry for CVE-2016-1546
- NVD CVE-2016-1546
- Apache mod_http2 documentation
- Debian security tracker CVE-2016-1546
- Ubuntu CVE-2016-1546 status
- CISA Known Exploited Vulnerabilities Catalog
- Imperva HTTP/2 in-depth analysis report
- PRETT2 academic paper referencing CVE-2016-1546
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.