Back to Blog
critical SEVERITY5 min read

How Unsafe Random Function Vulnerabilities Happen in Node.js and How to Fix Them

A critical vulnerability (CVE-2025-7783) was discovered in the popular `form-data` npm package where an unsafe random function was used to generate boundary strings for multipart form data. This weakness could allow attackers to predict boundary values and potentially inject malicious content into HTTP requests. The fix upgrades form-data to patched versions (2.5.4, 3.0.4, or 4.0.4) that use cryptographically secure random number generation.

O
By Orbis AppSec
Published August 21, 2026Reviewed August 21, 2026

Answer Summary

CVE-2025-7783 is a critical vulnerability in the Node.js `form-data` package (CWE-330: Use of Insufficiently Random Values) where `Math.random()` was used to generate multipart boundary strings instead of cryptographically secure alternatives. Attackers could predict these boundaries to manipulate HTTP request parsing. The fix requires upgrading form-data to version 2.5.4, 3.0.4, or 4.0.4, which replace the weak random function with `crypto.randomBytes()`.

Vulnerability at a Glance

cweCWE-330
fixUpgrade form-data to 2.5.4, 3.0.4, or 4.0.4
riskRequest manipulation, content injection, authentication bypass
languageJavaScript/Node.js
root causeform-data used Math.random() for boundary generation instead of crypto.randomBytes()
vulnerabilityUnsafe Random Function (Insufficient Randomness)

Introduction

The form-data package in the project's package-lock.json was flagged with a critical severity rating due to CVE-2025-7783—a vulnerability stemming from the use of an unsafe random function. This package, pinned at version 4.0.0 in the dependency tree, was generating multipart form boundaries using Math.random(), a function that produces predictable values unsuitable for security-sensitive operations.

Looking at the package.json diff, we can see the vulnerable dependency declaration:

// Before (vulnerable)
"form-data": "^4.0.0",

This seemingly innocuous version constraint exposed the application to a critical attack vector where boundary strings in multipart HTTP requests could be predicted and exploited.

The Vulnerability Explained

What Makes Math.random() Dangerous?

The form-data package is used extensively in Node.js applications to construct multipart/form-data streams for file uploads and API requests. Each multipart request requires a unique boundary string to separate different parts of the payload. The vulnerable versions of form-data generated these boundaries using JavaScript's built-in Math.random() function.

The problem? Math.random() is a pseudo-random number generator (PRNG) that uses a deterministic algorithm. Given enough samples of its output, an attacker can:

  1. Reverse-engineer the internal state of the PRNG
  2. Predict future boundary values with high accuracy
  3. Craft malicious requests that exploit boundary prediction

Attack Scenario Specific to This Application

Consider how this vulnerability could be exploited in the affected codebase. The package.json shows this is a feature-rich application with multiple HTTP-related dependencies including cloudscraper, cors, node-fetch, and various API integrations (google-tts-api, groq-sdk, mal-scraper).

An attacker could:

  1. Observe multiple requests from the application to determine the PRNG state
  2. Predict the next boundary string that form-data will generate
  3. Inject a crafted payload that includes the predicted boundary, allowing them to:
    - Append additional form fields to legitimate requests
    - Modify file upload contents mid-stream
    - Bypass content validation that relies on boundary integrity

For example, if this application uses form-data to upload files to external services (like the megajs or pastebin-js integrations visible in the dependencies), an attacker could potentially inject malicious content into those uploads.

Real-World Impact

The severity is rated CRITICAL because:

  • Authentication bypass: If form data contains authentication tokens, boundary prediction enables token injection
  • Data manipulation: File uploads can be corrupted or replaced
  • Server-side request forgery (SSRF): Crafted boundaries could trick servers into parsing attacker-controlled content
  • Cache poisoning: Predictable boundaries enable cache key manipulation attacks

The Fix

The remediation is straightforward but critical—upgrade form-data to a patched version that uses cryptographically secure random number generation.

Before (Vulnerable)

{
  "form-data": "^4.0.0"
}

After (Fixed)

{
  "form-data": "^4.0.6"
}

The diff shows the precise change in package.json:

-        "form-data": "^4.0.0",
+        "form-data": "^4.0.6",

What Changed Internally

The patched versions (2.5.4, 3.0.4, and 4.0.4+) replace the boundary generation logic:

Vulnerable code pattern (conceptual):

// OLD: Predictable boundary generation
function generateBoundary() {
  return '--------------------------' + Math.random().toString(36).slice(2);
}

Fixed code pattern:

// NEW: Cryptographically secure boundary generation
const crypto = require('crypto');

function generateBoundary() {
  return '--------------------------' + crypto.randomBytes(16).toString('hex');
}

The crypto.randomBytes() function draws from the operating system's cryptographically secure random number generator (CSPRNG), making boundary prediction computationally infeasible.

Additional Dependency Updates

The PR also updates several other packages to ensure compatibility and address other potential issues:

-        "fluent-ffmpeg": "^2.1.3",
+        "fluent-ffmpeg": "^2.1.5",

-        "moment-timezone": "^0.5.34",
+        "moment-timezone": "^0.5.43",

-        "node-webpmux": "^3.1.0",
+        "node-webpmux": "^3.1.7",

These updates ensure the dependency tree remains consistent and doesn't inadvertently pull in vulnerable transitive dependencies.

Prevention & Best Practices

1. Audit Dependencies Regularly

# Run npm's built-in security audit
npm audit

# Use Trivy for comprehensive scanning
trivy fs --scanners vuln .

2. Never Use Math.random() for Security

When generating any security-sensitive values in Node.js, always use the crypto module:

const crypto = require('crypto');

// For random strings
const secureToken = crypto.randomBytes(32).toString('hex');

// For UUIDs (Node.js 14.17+)
const secureUUID = crypto.randomUUID();

3. Pin and Lock Dependencies

Use package-lock.json or yarn.lock to ensure reproducible builds, but regularly update to incorporate security patches:

# Update a specific package to its latest patched version
npm update form-data

# Or install a specific safe version
npm install form-data@4.0.6

4. Implement Dependency Scanning in CI/CD

Add automated vulnerability scanning to your pipeline:

# Example GitHub Actions workflow
- name: Run Trivy vulnerability scanner
  uses: aquasecurity/trivy-action@master
  with:
    scan-type: 'fs'
    scan-ref: '.'
    severity: 'CRITICAL,HIGH'

5. Follow the Principle of Least Authority

Only install dependencies you actually need. The package.json in this project shows numerous dependencies—each one increases the attack surface.

Key Takeaways

  • The form-data package before version 4.0.4 used Math.random() for boundary generation, making multipart requests predictable and exploitable
  • CVE-2025-7783 affects multiple major version lines—ensure you're on 2.5.4+, 3.0.4+, or 4.0.4+ depending on your version constraint
  • Boundary prediction attacks can lead to request manipulation, content injection, and authentication bypass in applications handling file uploads or API integrations
  • Always use crypto.randomBytes() or crypto.randomUUID() in Node.js for any value that needs to be unpredictable
  • Transitive dependencies matter—even if you don't directly use form-data, other packages like axios, request, or got may depend on it

How Orbis AppSec Detected This

  • Source: The form-data package's internal boundary generation function
  • Sink: HTTP request boundary strings used in multipart/form-data encoding
  • Missing control: Cryptographically secure random number generation was not used for boundary string creation
  • CWE: CWE-330 (Use of Insufficiently Random Values)
  • Fix: Upgraded form-data from version 4.0.0 to 4.0.6, which replaces Math.random() with crypto.randomBytes() for boundary generation

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

CVE-2025-7783 serves as a stark reminder that even well-established npm packages can harbor critical vulnerabilities in seemingly mundane functionality. The use of Math.random() for security-sensitive operations is a common anti-pattern that continues to surface in production code.

By upgrading form-data to version 4.0.6 (or the appropriate patched version for your major version line), you eliminate the risk of boundary prediction attacks. More importantly, this incident underscores the need for:

  1. Continuous dependency monitoring in your development workflow
  2. Understanding the security implications of the packages you depend on
  3. Automated security scanning to catch issues before they reach production

Stay vigilant, keep your dependencies updated, and always question whether the random values in your code are truly random enough for their purpose.

References

Frequently Asked Questions

What is an unsafe random function vulnerability?

An unsafe random function vulnerability occurs when cryptographically weak random number generators like Math.random() are used for security-sensitive operations such as generating tokens, boundaries, or session IDs, making values predictable to attackers.

How do you prevent unsafe random function vulnerabilities in Node.js?

Use the built-in crypto module's randomBytes() or randomUUID() functions for any security-sensitive random value generation, and audit dependencies for known vulnerabilities using npm audit or security scanners.

What CWE is unsafe random function?

CWE-330: Use of Insufficiently Random Values covers vulnerabilities where weak or predictable random number generators are used in security contexts.

Is using Math.random() ever safe for security purposes?

No, Math.random() is never safe for security purposes as it uses a predictable pseudo-random number generator (PRNG) that can be reverse-engineered, making generated values guessable by attackers.

Can static analysis detect unsafe random function vulnerabilities?

Yes, static analysis tools like Trivy, Semgrep, and npm audit can detect known CVEs in dependencies and flag direct usage of Math.random() in security-sensitive contexts.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #2

Related Articles

critical

How Command Injection via Unescaped Line Terminators Happens in Node.js and How to Fix It

A critical command injection vulnerability (CVE-2026-9277) was discovered in the shell-quote npm package version 1.8.3, where unescaped line terminators could allow attackers to execute arbitrary code. This fix upgrades shell-quote to version 1.9.0 using npm overrides to ensure all instances in the dependency tree are patched, eliminating the attack vector across the entire application.

critical

How Distributed Lock Takeover Happens in Node.js and How to Fix It

A critical vulnerability in `redis-lock/server.mjs` allowed any authenticated client to release another client's lock by guessing predictable holder identifiers like process IDs or hostnames. The fix implements cryptographically random `lockId` values that are minted on lock acquisition and validated on release, eliminating the exploit primitive entirely.

high

How Denial of Service via Infinite Loop happens in JavaScript (nanoid) and how to fix it

A high-severity denial of service vulnerability (CVE-2026-67213) was discovered in nanoid versions before 5.1.6 and 3.3.18, where the `customAlphabet` function could enter an infinite loop during random ID generation. The fix upgrades the transitive nanoid dependency from 3.3.16 to 3.3.18 using pnpm overrides, ensuring the vulnerable code path is eliminated from the entire dependency tree including PostCSS.

high

How Information Disclosure via Unstripped Credential Headers Happens in Electron Apps and How to Fix It

A high-severity vulnerability (CVE-2026-54673) in the builder-util-runtime package allowed sensitive credential headers to leak during HTTP redirects in Electron applications. The fix upgrades builder-util-runtime from version 9.5.1 to 9.7.0, which properly strips authentication headers before following redirects to prevent information disclosure.

high

How Command Injection happens in PHP and how to fix it

A high-severity command injection vulnerability was discovered in `lib/Controller/Helper.php` where the `corruptline()` method used `exec()` to run sed and awk commands with user-controlled input. The fix replaced all shell command execution with native PHP file operations using `SplFileObject`, eliminating the command injection attack surface entirely.

high

How Missing CSRF Middleware happens in Express.js and how to fix it

A high-severity CSRF vulnerability was discovered in `libProxy.js` of an Express.js application — the app had no CSRF middleware protecting its state-changing routes, leaving them open to cross-site request forgery attacks. The fix introduces a `csrf` token library, a `/csrf-token` endpoint to issue tokens, and a middleware that validates `x-csrf-token` headers or `_csrf` body fields on all non-safe HTTP methods. This proactive hardening removes an exploit primitive that could be chained with ot