CVE-2025-22150 - The Predictable Boundary Flaw in Undici http/1.1 Client (Exploit Breakdown & Fixes)
CVE-2025-22150 highlights how even popular and widely used Node.js libraries can fall to security lapses when basic randomness is underestimated. This exclusive long-read explains how Undici, the modern HTTP/1.1 client, introduced a risky bug in how it chooses multipart/form-data boundaries, why that matters, how attackers can exploit it, real-world code samples, and what you should do now.
What is Undici?
Undici is a fast HTTP/1.1 client, designed to outpace Node.js’s built-in http module. It is heavily used in production, including in frameworks like Fastify.
Multipart/form-data, used for things like file uploads, requires a unique “boundary” string so the server can split the multiple parts apart. This boundary needs to be unpredictable, especially in environments where requests could end up at attacker-controlled endpoints.
The Root of the Issue
Vulnerable Versions:
How was the boundary chosen?
// Vulnerable boundary generation code (simplified)
const BOUNDARY_CHARACTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let boundary = '';
for (let i = ; i < 24; i++) {
boundary += BOUNDARY_CHARACTERS[Math.floor(Math.random() * BOUNDARY_CHARACTERS.length)];
}
> Undici used JavaScript's built-in Math.random() to make the boundary string.
Why is this a problem?
Math.random() in JavaScript is not cryptographically secure. It can be *predicted* if enough outputs are sampled (see this Stack Overflow discussion). If an attacker observes a few boundaries from your app, they could compute what your next boundary will be.
An attacker can only do *actual* harm if
- Your application sends multipart/form-data requests to an attacker-controlled webserver (think: file upload, or sending logs/images).
- The attacker is able to see several boundary values (e.g., receives several requests from the system, or has another info leak).
The attacker predicts your next multipart boundary.
- The attacker uses that knowledge to craft a malicious request, potentially tampering with requests the backend expects to be unique.
Attacker controls an endpoint to which your app sends multipart requests.
2. Attacker records boundaries by inspecting Content-Type: multipart/form-data; boundary=... headers.
Attacker predicts boundaries your server will use next.
5. Attacker attempts boundary reuse: They could, in some complex cases, replay data, insert content, or cross boundaries between different users and requests.
Example
POST /upload HTTP/1.1
Host: attacker.site
Content-Type: multipart/form-data; boundary=AbXy789klm123opqz
...
--AbXy789klm123opqz
Content-Disposition: form-data; name="file"; filename="exploit.js"
Content-Type: application/javascript
// Malicious JS code
...
--AbXy789klm123opqz--
If the attacker can *predict* your app’s next boundary, then in rare but possible edge-cases, they could interfere with systems expecting boundaries to be unique and unpredictable.
Proof of Concept: Extracting Boundaries With a Fake Server
You can simulate the attack locally.
Here’s how an attacker would log boundary values
// Attacker's controlled Node.js server
const http = require('http');
http.createServer((req, res) => {
const contentType = req.headers['content-type'];
if (contentType && contentType.startsWith('multipart/form-data')) {
const boundary = contentType.match(/boundary=(.*)/)[1];
console.log('Leaked boundary:', boundary);
}
res.end('ok');
}).listen(808, () => console.log('Attacker listening on port 808'));
Now, every Undici-powered multipart POST from your code to http://attacker.site will have its boundary leaked.
The Core Problem: Should Math.random() Ever Be Used for Security?
No. For even mild security boundaries like this, always use crypto.randomBytes or similar, which is cryptographically secure.
New undici versions now use such secure APIs (see Undici PR #2737):
// Secure boundary generation (Node.js)
const { randomBytes } = require('crypto');
const boundary = randomBytes(24).toString('hex');
Avoid using multipart POSTs to untrusted or semi-trusted endpoints!
Workaround:
If you can't upgrade immediately, ensure your application does not send multipart POSTs to any attacker-controlled URLs. Audit your URL handling!
References & Further Reading
- Undici Security Advisory GHSA-pc3c-v647-gw29
- Undici PR #2737 (fixes the bug)
- OWASP: Cryptographically Secure Pseudo Random Number Generator (CSPRNG)
- Math.random() predictability discussion
Summary
- CVE-2025-22150 exposes how insecure random generation for multipart boundaries can be a real problem.
- If you use Undici in your Node.js stack, upgrade right now or stop multipart requests to untrusted targets.
Stay secure! ✨
*This write-up is exclusive and written for clarity by [AI]. For the latest details always refer to the official Undici repository and Node.js Security Advisories.*
Timeline
Published on: 01/21/2025 18:15:14 UTC