Oct 1, 2026·7 min read·2 visits
Unauthenticated remote HTTP/2 requests to Fastify endpoints utilizing response trailers trigger an uncaught validation exception in Node.js, immediately crashing the server.
A protocol validation vulnerability exists in Fastify before version 5.12.5. When serving requests over HTTP/2, Fastify unconditionally injects the forbidden Transfer-Encoding header when response trailers are used, triggering an uncaught exception in Node.js and crashing the process.
Fastify is an optimized web framework for the Node.js runtime environment. The framework relies on a highly structured request-response lifecycle to parse incoming payloads, execute middleware, run route handlers, and serialize outgoing responses. This architecture exposes an attack surface when specific HTTP protocol extensions are processed under mismatched transport configurations.
The vulnerability is classified under CWE-248 (Uncaught Exception) and is tracked as CVE-2026-92081. The flaw manifests when a route handler utilizes response trailers (via the reply.trailer() API) and is accessed over an active HTTP/2 connection. Under these specific circumstances, Fastify attempts to apply transport rules optimized for HTTP/1.1 to the HTTP/2 stream, leading to a fatal runtime execution failure.
The resulting impact is a complete denial of service. Because the exception is generated outside the primary execution context of the route handler, Fastify's standard request-lifecycle error catch blocks fail to intercept it. The error propagates directly to the top-level event loop of Node.js, causing the entire process to crash and forcing all active client connections to disconnect.
To understand the root cause of the vulnerability, the differences in trailer implementation between HTTP/1.1 and HTTP/2 must be examined. In HTTP/1.1, response trailers are headers sent after the response body payload has been fully transmitted. Because the receiver must know when the body ends and the trailers begin, HTTP/1.1 strictly mandates the use of Chunked Transfer Encoding. Fastify historically satisfied this protocol requirement by unconditionally injecting the Transfer-Encoding: chunked header into the response whenever a trailer was registered.
HTTP/2 diverges entirely from this model. It operates on a binary framing layer where headers, payload data, and trailing headers are encapsulated within dedicated frames, specifically HEADERS and DATA frames. Because the binary framing layer natively handles data boundaries, HTTP/2 does not support and explicitly forbids connection-specific headers, including Transfer-Encoding, as documented in Section 8.1.2.2 of RFC 7540 and RFC 9113.
When a client issues an HTTP/2 request to an endpoint with configured trailers, the vulnerable Fastify server processes the response and executes its end-of-send lifecycle hook. It evaluates the presence of trailers and writes Transfer-Encoding: chunked to the response headers. During the subsequent serialization process, Node.js's native http2 module inspects the outgoing headers. Upon detecting the prohibited Transfer-Encoding header, the runtime throws a synchronous ERR_HTTP2_INVALID_CONNECTION_HEADERS error.
This exception occurs during the low-level stream flush phase, which is decoupled from the synchronous execution flow of the route handler's async state machine. Consequently, the exception bypasses Fastify's internal error-routing mechanisms and bubbles up as an unhandled exception. In Node.js, an uncaught exception on the event loop triggers process termination, resulting in a denial of service.
The vulnerability is localized within the core response-finalization sequence of Fastify inside lib/reply.js. Prior to the patch, the onSendEnd function evaluated the registry of trailers and mutated the response headers without verifying the active protocol version of the underlying connection.
Below is the vulnerable logic inside lib/reply.js:
function onSendEnd (reply, payload) {
// ...
if (header !== '') {
// The framework unconditionally sets chunked encoding for HTTP/1.1 trailer compatibility
reply.header('Transfer-Encoding', 'chunked')
reply.header('Trailer', header.trim())
} else {
reply[kReplyTrailers] = null
}
// ...
}The fix, introduced in commit ad06a4c3fe8a944a904f38068249b18b8f552e90, introduces a protocol check using the internal helper function isHttp2Reply(reply). This utility identifies whether the active reply instance is bound to an HTTP/2 stream.
Below is the patched logic implementing the safety condition:
function onSendEnd (reply, payload) {
// ...
if (header !== '') {
// HTTP/1 must use chunked encoding for trailers. HTTP/2 forbids
// the transfer-encoding header and handles trailers natively.
if (!isHttp2Reply(reply)) {
reply.header('Transfer-Encoding', 'chunked')
}
reply.header('Trailer', header.trim())
} else {
reply[kReplyTrailers] = null
}
// ...
}By restricting the insertion of Transfer-Encoding to non-HTTP/2 replies, the framework ensures compliance with RFC 7540 and RFC 9113. The native Node.js HTTP/2 serialization layer receives only valid headers, neutralizing the condition that triggered the runtime exception.
Exploitation of CVE-2026-92081 is direct and requires no authentication. The attacker must target a Fastify instance that has HTTP/2 enabled and exposes at least one route containing a call to the reply.trailer() method.
The attack vector consists of a single, standard HTTP/2 request directed to the vulnerable route. Because the error is triggered purely by the header generation on the server side, the client does not need to send a malformed payload or high-frequency requests. The payload serialization on the server automatically initiates the crash sequence upon processing the request.
The following sequence diagram outlines the progression of the attack:
When the client initiates the request, Fastify executes the route handler and schedules the trailer evaluation. Upon completion of the handler, Fastify invokes onSendEnd and appends Transfer-Encoding: chunked. When the serializing layer of the Node.js http2 module processes the headers, it encounters the invalid token, terminates the stream, and throws a validation error. The exception escapes to the process level, causing the daemon to exit immediately.
The CVSS score for this vulnerability is 5.9 (Medium) with the vector CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H. The attack complexity is rated as high because the vulnerability depends on specific configuration parameters: the server must actively support HTTP/2 and must expose a route using trailers.
While the attack complexity is classified as high due to these prerequisites, the severity of successful exploitation is elevated. An attacker can repeatedly send the trigger request to keep the service in a perpetual restart loop. This disrupts service delivery for all clients, drops all in-flight requests on the affected instance, and neutralizes load-balancing configurations that route traffic to the affected node.
There is no risk of confidentiality loss or integrity compromise, as the flaw does not facilitate arbitrary code execution, file system access, or memory disclosure. The impact is confined to system availability. If the process manager (such as pm2 or Kubernetes pod controller) is configured to automatically restart crashed processes, the continuous termination of the process can lead to container throttling, increased CPU utilization, and eventual deployment lockout.
The primary remediation for this vulnerability is upgrading Fastify to version 5.12.5 or later. This release incorporates the protocol check that prevents the injection of Transfer-Encoding on HTTP/2 connection streams.
For deployments where an immediate upgrade is not feasible, developers can apply workarounds within their application code. One approach is to wrap the execution of response trailers with a check on the request's HTTP version. If the connection utilizes HTTP/2, the registration of the trailer should be bypassed:
fastify.get('/vulnerable-route', (request, reply) => {
// Apply trailers only if the connection is HTTP/1.1
if (request.raw.httpVersion.startsWith('1.')) {
reply.trailer('x-checksum', async () => 'computed-hash')
}
return { status: 'success' }
})Alternatively, if HTTP/2 functionality is not explicitly required by the business logic, the feature can be disabled globally during the instantiation of the Fastify server by setting the http2 parameter to false:
const fastify = require('fastify')({ http2: false })Security teams should also review their process manager configurations to ensure that aggressive restart strategies do not lead to resource exhaustion during active denial-of-service attempts. Implementing rate-limiting rules at the reverse proxy or Web Application Firewall (WAF) layer can help limit exposure by dropping suspicious HTTP/2 connections before they reach the backend Node.js application.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Fastify Fastify | < 5.12.5 | 5.12.5 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-248 |
| Attack Vector | Network |
| CVSS Score | 5.9 |
| Exploit Status | poc |
| KEV Status | Not Listed |
| Impact | Denial of Service (DoS) |
The application encounters an exception during runtime that is not handled, causing the runtime environment to terminate the process.
An input validation vulnerability in the virtualenv package allows local execution hijacking via configuration injection. When generating the pyvenv.cfg configuration file, user-controlled parameters such as prompt options are written verbatim without sanitizing line-boundary sequences. This allows attackers to inject arbitrary configuration options, causing the tool to read malicious base interpreter paths.
CVE-2026-102930 is a high-severity supply chain vulnerability in virtualenv prior to version 21.7.12. The download_wheel() function lacks integrity checks when dynamically fetching seed packages (such as pip or setuptools) over the network. This allows an attacker to intercept the network stream, replace packages with backdoored components, and achieve arbitrary code execution inside newly spawned virtual environments.
An algorithmic complexity vulnerability in the `league/commonmark` library's GitHub Flavored Markdown (GFM) Table extension allows remote, unauthenticated attackers to cause a Denial of Service (DoS) via high CPU consumption. By submitting a specially crafted Markdown payload containing an extremely long paragraph without letter characters or pipe symbols, the parser executes a quadratic-time $O(N^2)$ scanning operation that exhausts system resources.
An authenticated Server-Side Request Forgery (SSRF) and credential exfiltration vulnerability exists in LiteLLM proxy prior to versions 1.88.6 and 1.96.2. By bypassing sanitization logic through nested form-data parameters or using connection health checks, authenticated users can redirect outbound API calls to arbitrary endpoints, exposing sensitive upstream administrative credentials.
CVE-2026-91776 is a high-severity Denial of Service (DoS) vulnerability in the FasterXML jackson-databind library. The vulnerability is caused by uncontrolled resource consumption (CWE-400) where raw, unrecognized polymorphic type IDs are cached indefinitely without boundaries inside TypeDeserializerBase. When name-based polymorphic deserialization is configured with a fallback mechanism (such as a default implementation or custom problem handlers), remote attackers can send crafted payloads containing unique unknown type IDs, causing heap exhaustion, Garbage Collection (GC) overhead limit exhaustion, and an Out-of-Memory (OOM) crash.
An uncontrolled resource consumption vulnerability in FasterXML jackson-databind allows remote unauthenticated attackers to cause a Denial of Service (DoS) via crafted JSON payloads containing out-of-order forward references in identity-enabled collections or maps.