VYPR
Medium severity6.8NVD Advisory· Published Jan 21, 2025· Updated Apr 15, 2026

CVE-2025-22150

CVE-2025-22150

Description

Undici is an HTTP/1.1 client. Starting in version 4.5.0 and prior to versions 5.28.5, 6.21.1, and 7.2.3, undici uses Math.random() to choose the boundary for a multipart/form-data request. It is known that the output of Math.random() can be predicted if several of its generated values are known. If there is a mechanism in an app that sends multipart requests to an attacker-controlled website, they can use this to leak the necessary values. Therefore, an attacker can tamper with the requests going to the backend APIs if certain conditions are met. This is fixed in versions 5.28.5, 6.21.1, and 7.2.3. As a workaround, do not issue multipart requests to attacker controlled servers.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
undicinpm
>= 4.5.0, < 5.28.55.28.5
undicinpm
>= 6.0.0, < 6.21.16.21.1
undicinpm
>= 7.0.0, < 7.2.37.2.3

Patches

6
711e20772764

Backport of c2d78cd

https://github.com/nodejs/undiciMatteo CollinaJan 16, 2025via ghsa
1 file changed · +9 1
  • lib/fetch/body.js+9 1 modified
    @@ -22,6 +22,14 @@ const { isUint8Array, isArrayBuffer } = require('util/types')
     const { File: UndiciFile } = require('./file')
     const { parseMIMEType, serializeAMimeType } = require('./dataURL')
     
    +let random
    +try {
    +  const crypto = require('node:crypto')
    +  random = (max) => crypto.randomInt(0, max)
    +} catch {
    +  random = (max) => Math.floor(Math.random(max))
    +}
    +
     let ReadableStream = globalThis.ReadableStream
     
     /** @type {globalThis['File']} */
    @@ -107,7 +115,7 @@ function extractBody (object, keepalive = false) {
         // Set source to a copy of the bytes held by object.
         source = new Uint8Array(object.buffer.slice(object.byteOffset, object.byteOffset + object.byteLength))
       } else if (util.isFormDataLike(object)) {
    -    const boundary = `----formdata-undici-0${`${Math.floor(Math.random() * 1e11)}`.padStart(11, '0')}`
    +    const boundary = `----formdata-undici-0${`${random(1e11)}`.padStart(11, '0')}`
         const prefix = `--${boundary}\r\nContent-Disposition: form-data`
     
         /*! formdata-polyfill. MIT License. Jimmy Wärting <https://jimmy.warting.se/opensource> */
    
c2d78cd19fe4

Merge commit from fork

https://github.com/nodejs/undiciMatteo CollinaJan 16, 2025via ghsa
1 file changed · +9 1
  • lib/web/fetch/body.js+9 1 modified
    @@ -17,6 +17,14 @@ const { isErrored, isDisturbed } = require('node:stream')
     const { isArrayBuffer } = require('node:util/types')
     const { serializeAMimeType } = require('./data-url')
     const { multipartFormDataParser } = require('./formdata-parser')
    +let random
    +
    +try {
    +  const crypto = require('node:crypto')
    +  random = (max) => crypto.randomInt(0, max)
    +} catch {
    +  random = (max) => Math.floor(Math.random(max))
    +}
     
     const textEncoder = new TextEncoder()
     function noop () {}
    @@ -110,7 +118,7 @@ function extractBody (object, keepalive = false) {
         // Set source to a copy of the bytes held by object.
         source = new Uint8Array(object.buffer.slice(object.byteOffset, object.byteOffset + object.byteLength))
       } else if (webidl.is.FormData(object)) {
    -    const boundary = `----formdata-undici-0${`${Math.floor(Math.random() * 1e11)}`.padStart(11, '0')}`
    +    const boundary = `----formdata-undici-0${`${random(1e11)}`.padStart(11, '0')}`
         const prefix = `--${boundary}\r\nContent-Disposition: form-data`
     
         /*! formdata-polyfill. MIT License. Jimmy Wärting <https://jimmy.warting.se/opensource> */
    
c3acc6050b78

Merge commit from fork

https://github.com/nodejs/undiciMatteo CollinaJan 16, 2025via ghsa
1 file changed · +9 1
  • lib/web/fetch/body.js+9 1 modified
    @@ -20,6 +20,14 @@ const { isErrored, isDisturbed } = require('node:stream')
     const { isArrayBuffer } = require('node:util/types')
     const { serializeAMimeType } = require('./data-url')
     const { multipartFormDataParser } = require('./formdata-parser')
    +let random
    +
    +try {
    +  const crypto = require('node:crypto')
    +  random = (max) => crypto.randomInt(0, max)
    +} catch {
    +  random = (max) => Math.floor(Math.random(max))
    +}
     
     const textEncoder = new TextEncoder()
     function noop () {}
    @@ -113,7 +121,7 @@ function extractBody (object, keepalive = false) {
         // Set source to a copy of the bytes held by object.
         source = new Uint8Array(object.buffer.slice(object.byteOffset, object.byteOffset + object.byteLength))
       } else if (util.isFormDataLike(object)) {
    -    const boundary = `----formdata-undici-0${`${Math.floor(Math.random() * 1e11)}`.padStart(11, '0')}`
    +    const boundary = `----formdata-undici-0${`${random(1e11)}`.padStart(11, '0')}`
         const prefix = `--${boundary}\r\nContent-Disposition: form-data`
     
         /*! formdata-polyfill. MIT License. Jimmy Wärting <https://jimmy.warting.se/opensource> */
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

9

News mentions

0

No linked articles in our index yet.