Like a fire sprinkler that floods the office — but only if you installed a rare ceiling tile and left the test valve open
CVE-2026-92081 affects the Fastify web framework for Node.js in all versions prior to 5.12.5. When a route registers a response trailer via reply.trailer() and the request arrives over HTTP/2, Fastify unconditionally injects a Transfer-Encoding: chunked header — a header that HTTP/2 explicitly forbids. Node.js throws while serializing the response, producing an uncaught exception (CWE-248) that kills the entire process. Every in-flight request is dropped. The crash is repeatable on every restart, meaning a single attacker can loop and keep the service down indefinitely.
The vendor's MEDIUM / 5.9 rating is directionally correct but slightly generous. The CVSS vector scores AC:H (high attack complexity), which acknowledges the narrow trigger conditions, but the score still overweights the unauthenticated-remote posture without discounting for two compounding prerequisites: the service must expose HTTP/2 *directly* to the Fastify process (most production deployments terminate HTTP/2 at a reverse proxy like Nginx, ALB, or Cloudflare), and at least one route must use the reply.trailer() API, which is uncommon in real codebases. When both conditions align the bug is trivially weaponizable — one crafted request crashes the server — but the population of deployments meeting both conditions is small. A reassessed score of 5.0 better reflects real-world exposure.
4 steps from start to impact.
Identify a Fastify HTTP/2 endpoint
server response header or ALPN negotiation. If the target sits behind a reverse proxy that terminates HTTP/2, this step fails — the proxy downgrades to HTTP/1.1 before traffic reaches Fastify.- Target exposes Fastify directly on HTTP/2 (no TLS-terminating reverse proxy in front)
- Most production Fastify deployments sit behind Nginx, HAProxy, AWS ALB, or a CDN that terminates HTTP/2 and forwards HTTP/1.1
- Default Fastify configuration uses HTTP/1.1; HTTP/2 requires explicit opt-in via
http2: true
h2 in TLS handshake confirms HTTP/2 supportLocate a route using reply.trailer()
reply.trailer() to register at least one response trailer. This is a relatively niche Fastify API used primarily for streaming integrity checks (e.g., content checksums). Enumerating which routes use trailers may require fuzzing or knowledge of the application codebase.- At least one route in the application uses
reply.trailer()
reply.trailer()is an uncommon API — most Fastify apps never call it- Attacker has no way to remotely enumerate which routes use trailers without sending requests and observing responses
Send a single HTTP/2 request to the trailer route
Transfer-Encoding: chunked on the response, Node.js rejects it as an illegal HTTP/2 header, and the process throws an uncaught exception. The entire Node.js process terminates. No special payload is needed — any valid HTTP/2 request to the route triggers the crash.- Network reachability to the Fastify HTTP/2 port
- Process managers (PM2, systemd, Kubernetes) will auto-restart the process, limiting sustained impact
- Rate limiting or connection limits at the load balancer may slow repeated crashes
ERR_HTTP2_INVALID_HEADER_VALUE or similar Node.js uncaught exception; crash-loop alerts in Kubernetes or PM2 will fireLoop to sustain denial of service
- Continued network access to the target
- Kubernetes CrashLoopBackOff increases restart intervals, giving defenders time to react
- WAF or IP-based rate limiting can block the attacker's source after initial crashes
- Health check failures will remove the pod from the service mesh, limiting blast radius to that replica
The supporting signals.
| In-the-wild exploitation | No known exploitation. Not listed on CISA KEV. No campaigns or threat actor usage reported as of 2026-09-17. |
|---|---|
| Proof-of-concept | No public PoC found. Exploitation is trivial (single HTTP/2 request to a trailer route), so a weaponized script could be written in minutes, but none has surfaced on GitHub or exploit databases yet. |
| EPSS | 0.00395 (0.4% probability of exploitation in next 30 days) — bottom quartile, consistent with a niche DoS bug. |
| KEV status | Not listed. No CISA KEV entry as of 2026-09-17. |
| CVSS vector | CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H — Network-reachable, high complexity, no privileges or user interaction, availability-only impact. The AC:H reflects the dual prerequisite of HTTP/2 + trailer usage. |
| Affected versions | Fastify < 5.12.5 (all 5.x releases through 5.12.4; also affects 4.x if still in use, though 4.x is EOL). |
| Fixed version | Fastify 5.12.5 (released 2026-09-16). |
| Scanning / exposure | Fastify has ~8.5 million weekly npm downloads. However, direct HTTP/2 exposure to Fastify (without a terminating proxy) is a small fraction of that install base. No Shodan/Censys dork reliably identifies vulnerable instances. |
| Disclosure date | 2026-09-16 via GitHub Security Advisory GHSA-4mh8-r7rc-xpvc. |
| Reporter | Disclosed via OpenJS Foundation security process. Specific researcher not publicly credited in the advisory. |
noisgate verdict.
The single most decisive factor is the compound prerequisite narrowing: exploitation requires both direct HTTP/2 termination at the Fastify process (uncommon — most deployments proxy HTTP/2 upstream) *and* use of the niche reply.trailer() API, drastically shrinking the reachable population. The impact ceiling is availability-only (process crash), with no path to code execution, data exfiltration, or lateral movement.
Why this verdict
- Dual prerequisite gate: The bug only fires when HTTP/2 reaches Fastify directly *and* a route uses
reply.trailer(). Each condition independently eliminates a large fraction of the install base; combined, the reachable population is very small. - Availability-only impact: The worst outcome is a process crash (DoS). There is no memory corruption, no code execution, no data leak. The CVSS vector confirms C:N/I:N/A:H.
- Auto-restart dampening: Modern deployments run Fastify under PM2, systemd, or Kubernetes, all of which auto-restart crashed processes. Sustained DoS requires the attacker to maintain a loop, which is detectable and blockable.
- Role multiplier: Fastify is an application-tier web framework. It is *not* an identity provider, hypervisor, domain controller, kernel agent, or network edge appliance. (a) *Low-value role (dev/sandbox):* chain succeeds if both conditions met — blast radius is one dev process, negligible. (b) *Typical role (API microservice behind a load balancer):* HTTP/2 is almost always terminated at the LB/proxy, so the chain usually fails; if it succeeds, blast radius is one replica pod, mitigated by auto-restart. (c) *High-value role (API gateway):* conceivable but uncommon; even here, the impact is DoS of one process, not domain/fleet/supply-chain compromise. No high-value role scenario reaches the blast radius floor for a HIGH verdict.
- No exploitation pressure: EPSS is 0.4%, no KEV listing, no public PoC, no observed campaigns. The bug has been public for one day with zero weaponization signals.
Why not higher?
Upgrading to HIGH would require either a path to code execution, a broader reachable population, or active exploitation — none of which exist. The dual prerequisite (HTTP/2 + trailer API) compresses the exposed population well below 10% of the Fastify install base, and the impact ceiling is a recoverable process crash with no confidentiality or integrity consequences.
Why not lower?
Dropping to LOW would undercount the risk for the narrow set of deployments that *do* expose HTTP/2 directly and use trailers. In those environments, the crash is trivially repeatable, unauthenticated, and can sustain a service outage. The 8.5M weekly download footprint means even a small percentage translates to a non-trivial absolute number of vulnerable services.
What to do — in priority order.
- Remove reply.trailer() calls from HTTP/2 routes — The vendor-documented workaround. Audit your codebase for
reply.trailer()usage and remove or conditionally disable it when the connection is HTTP/2. This eliminates the trigger entirely. Apply immediately if you cannot upgrade within the 365-day noisgate remediation SLA. - Terminate HTTP/2 at the reverse proxy — Configure Nginx, HAProxy, AWS ALB, or Cloudflare to terminate HTTP/2 and forward HTTP/1.1 to Fastify. This prevents the illegal header from being generated. Most production deployments already do this — verify yours does.
- Enable crash-loop alerting — Ensure your process manager (PM2, systemd, Kubernetes) alerts on repeated restarts. Set a CrashLoopBackOff threshold to page on-call if the process crashes more than 3 times in 5 minutes, so you can respond to active exploitation quickly.
- Rate-limit HTTP/2 connections at the edge — Apply per-IP connection rate limits at your load balancer or WAF to slow an attacker's ability to repeatedly crash the process on every restart.
- WAF payload inspection — the crash is triggered by a normal, well-formed HTTP/2 request with no malicious payload. There is no signature to match; the bug is in how Fastify constructs the *response*, not in the request content.
- Node.js
process.on('uncaughtException')handler — while this can catch the throw and prevent process exit, it leaves the HTTP/2 session in an undefined state. The Fastify team does not recommend this as a mitigation; it may cause memory leaks or hung connections.
Crowdsourced verification payload.
Run this on any host with node and npm installed to check whether the installed fastify version is vulnerable. No special privileges needed. Example: bash check_cve_2026_92081.sh /path/to/your/project
#!/usr/bin/env bash
# CVE-2026-92081 - Fastify HTTP/2 trailer crash check
# Usage: bash check_cve_2026_92081.sh [project_dir]
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN
set -euo pipefail
PROJECT_DIR="${1:-.}"
if [ ! -d "$PROJECT_DIR/node_modules/fastify" ]; then
echo "UNKNOWN - fastify not found in $PROJECT_DIR/node_modules"
exit 2
fi
VERSION=$(node -e "try { console.log(require('$PROJECT_DIR/node_modules/fastify/package.json').version) } catch(e) { console.log('error') }")
if [ "$VERSION" = "error" ]; then
echo "UNKNOWN - could not read fastify version"
exit 2
fi
echo "Detected fastify version: $VERSION"
# Compare versions - 5.12.5 is the fix
FIXED="5.12.5"
version_gte() {
[ "$(printf '%s\n' "$1" "$2" | sort -V | head -n1)" = "$2" ]
}
if version_gte "$VERSION" "$FIXED"; then
echo "PATCHED - fastify $VERSION >= $FIXED"
exit 0
else
echo "VULNERABLE - fastify $VERSION < $FIXED (CVE-2026-92081)"
echo "Upgrade: npm install fastify@^5.12.5"
exit 1
fiIf you remember one thing.
reply.trailer() usage). There is no noisgate mitigation SLA for MEDIUM — go straight to the 365-day noisgate remediation SLA. Practically: upgrade to Fastify 5.12.5 in your next regular dependency update cycle. If you know you have HTTP/2 routes using reply.trailer(), either remove the trailer calls or confirm HTTP/2 is terminated at your reverse proxy — do that this week as a precaution. There is no active exploitation and no public PoC, so this does not warrant emergency patching or a weekend deploy. Put it in your next sprint's dependency bump and move on.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.