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

high

How Denial of Service via Infinite Loop Happens in JavaScript Dependencies and How to Fix It

CVE-2026-67213 is a high-severity denial of service vulnerability in nanoid before version 5.1.6 that triggers an infinite loop during random ID generation when processing specially crafted input. We upgraded nanoid across the entire dependency tree to patch this flaw and prevent attackers from freezing application threads. This fix ensures that ID generation remains resilient even when handling adversarial input patterns.

high

How Sensitive Data Exposure happens in Zotero plugins and how to fix it

A high-severity data exposure vulnerability in `Zotero.ts` automatically transmitted complete document metadata—including private notes, attachment paths, and tags—to external LLM services without user consent. The fix replaces broad `item.toJSON()` serialization with explicit field selection, sending only essential bibliographic data.

high

How missing dependency update cooldowns happen in GitHub Dependabot configurations and how to fix it

A semgrep scan flagged `.github/dependabot.yml` for lacking a cooldown period, meaning Dependabot would immediately propose updates to brand-new package versions across npm, Bundler, and Docker ecosystems. The fix adds a `cooldown: default-days: 7` block to every `package-ecosystem` entry, forcing a one-week waiting period before newly published releases are considered — reducing exposure to malicious or unstable package drops.

high

How dependabot-missing-cooldown happens in GitHub Actions/Node.js and how to fix it

The repository's `.github/dependabot.yml` had no cooldown period configured, meaning Dependabot could immediately propose updates to newly published package versions with zero time for the community to flag malware or instability. The fix adds a `cooldown` block with `default-days: 7` to both the `npm` and `github-actions` ecosystems, forcing a 7-day waiting period before new releases are surfaced as update PRs.

high

How Path Traversal Happens in TensorFlow's Data Service and How to Fix It

TensorFlow's data service dispatcher validated dataset IDs against forward-slash traversal attacks but overlooked backslash characters on non-Windows platforms, allowing attackers to escape the root directory. A targeted fix adds explicit backslash validation across all platforms, closing a high-severity path traversal vulnerability in the snapshot management system.

critical

How Unbounded WebSocket Message Handling Causes Resource Exhaustion in Node.js and How to Fix It

The WebSocketCrossServerAdapter class in a popular Node.js WebSocket library lacked any rate limiting on inbound messages, allowing attackers to flood Redis nodes and WebSocket servers with high-volume traffic. The fix introduces a configurable `rateLimit` option that caps messages per connection per second, preventing resource exhaustion while preserving legitimate functionality.