Back to Blog
high SEVERITY5 min read

How Denial of Service via excessive memory allocation happens in Node.js adm-zip and how to fix it

A high-severity Denial of Service vulnerability (CVE-2026-39244) was discovered in adm-zip versions prior to 0.6.0, affecting the laliga-fantasy-app. Attackers could craft malicious ZIP files that trigger excessive memory allocation, potentially crashing the web service. The fix involved upgrading adm-zip from version 0.5.16 to 0.6.0, which includes proper memory allocation bounds checking.

O
By Orbis AppSec
Published July 22, 2026Reviewed July 22, 2026

Answer Summary

CVE-2026-39244 is a Denial of Service vulnerability in the Node.js adm-zip library (versions before 0.6.0) where crafted ZIP files can cause excessive memory allocation, crashing applications. This is related to CWE-400 (Uncontrolled Resource Consumption). The fix requires upgrading adm-zip to version 0.6.0 or later, which implements proper bounds checking on memory allocation during ZIP file processing.

Vulnerability at a Glance

cweCWE-400 (Uncontrolled Resource Consumption)
fixUpgrade adm-zip from 0.5.16 to 0.6.0
riskRemote attackers can crash web services by uploading malicious ZIP files
languageNode.js (JavaScript)
root causeadm-zip 0.5.16 lacks bounds checking on memory allocation when parsing ZIP file headers
vulnerabilityDenial of Service via excessive memory allocation

Introduction

The laliga-fantasy-app, a Node.js web service for fantasy sports, was running with a critical security flaw hiding in plain sight within its package-lock.json. The adm-zip library at version 0.5.16—used for handling ZIP file operations—contained CVE-2026-39244, a high-severity Denial of Service vulnerability that could allow remote attackers to crash the entire application with a single malicious file upload.

Since this is a web service where request handlers are directly exposed to the internet, any user-influenced ZIP file processing becomes a potential attack vector. An attacker wouldn't need authentication or special privileges—just the ability to send a crafted ZIP file to any endpoint that processes compressed archives.

The Vulnerability Explained

What Makes This Dangerous

CVE-2026-39244 exploits a fundamental flaw in how adm-zip 0.5.16 handles ZIP file parsing. When the library reads a ZIP file's central directory and local file headers, it trusts the declared uncompressed size values without proper validation. A malicious ZIP file can declare astronomically large uncompressed sizes while remaining tiny in its compressed form.

Here's what the vulnerable dependency looked like in package.json:

"dependencies": {
  "adm-zip": "^0.5.16",
  "axios": "^1.6.2",
  // ... other dependencies
}

And in package-lock.json, the resolved version:

"node_modules/adm-zip": {
  "version": "0.5.16",
  "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz",
  "integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==",
  "license": "MIT",
  "engines": {
    "node": ">=12.0"
  }
}

Attack Scenario

Imagine an attacker crafting a ZIP file with the following characteristics:
- Compressed size: 1 KB
- Declared uncompressed size: 10 GB (or more)

When the laliga-fantasy-app attempts to process this file using adm-zip 0.5.16, the library allocates memory buffers based on the declared uncompressed size. This causes:

  1. Immediate memory spike: Node.js attempts to allocate gigabytes of memory
  2. Process crash: The V8 heap limit is exceeded, triggering an out-of-memory error
  3. Service unavailability: The web service goes down, affecting all users

For a fantasy sports application, this could mean:
- Users unable to set their lineups before match deadlines
- Lost transactions during peak usage periods
- Potential cascading failures if the app is part of a larger microservices architecture

The "ZIP Bomb" Variant

This vulnerability is related to the classic "ZIP bomb" attack pattern, but specifically targets the memory allocation phase rather than disk space. Traditional ZIP bombs expand to fill disk space; this attack exhausts RAM before any data is even decompressed.

The Fix

The remediation was straightforward but critical: upgrade adm-zip to version 0.6.0, which includes proper bounds checking on memory allocation.

Before (Vulnerable)

// package.json
"dependencies": {
  "adm-zip": "^0.5.16",
  // ...
}

// package-lock.json
"node_modules/adm-zip": {
  "version": "0.5.16",
  "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz",
  "engines": {
    "node": ">=12.0"
  }
}

After (Fixed)

// package.json
"dependencies": {
  "adm-zip": "^0.6.0",
  // ...
}

// package-lock.json
"node_modules/adm-zip": {
  "version": "0.6.0",
  "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.6.0.tgz",
  "integrity": "sha512-XleryMhbuksdKtofnWZ9Sk+4CUTbms4Mb/EU32SZwToAyZ5RgVos/ki8n+yr0LWHOGKuakbXTuuYNHLQjhddgg==",
  "engines": {
    "node": ">=14.0"
  }
}

What Changed in adm-zip 0.6.0

The new version implements several protective measures:

  1. Memory allocation limits: The library now validates declared sizes against reasonable thresholds before allocating buffers
  2. Decompression ratio checks: Suspicious compression ratios trigger warnings or rejections
  3. Incremental processing: Large files are processed in chunks rather than loading entirely into memory
  4. Node.js version requirement: The minimum Node.js version increased from 12.0 to 14.0, ensuring access to newer security APIs

The application version was also bumped from 3.4.1 to 3.5.3 to reflect this security update.

Prevention & Best Practices

1. Keep Dependencies Updated

Use automated dependency scanning in your CI/CD pipeline:

# Run Trivy to scan for vulnerable dependencies
trivy fs --scanners vuln .

# Or use npm audit
npm audit

2. Implement Defense in Depth

Even with patched libraries, add application-level protections:

// Example: Limit upload sizes at the application level
const express = require('express');
const app = express();

// Limit request body size
app.use(express.json({ limit: '10mb' }));

// For file uploads, use multer with limits
const multer = require('multer');
const upload = multer({
  limits: {
    fileSize: 50 * 1024 * 1024, // 50MB max
  }
});

3. Set Node.js Memory Limits

Configure memory limits to prevent runaway allocation from crashing your entire system:

# Limit Node.js heap to 512MB
node --max-old-space-size=512 app.js

4. Use Process Managers with Restart Policies

Deploy with PM2 or similar tools that automatically restart crashed processes:

// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'laliga-fantasy-app',
    script: 'app.js',
    max_memory_restart: '500M',
    restart_delay: 1000
  }]
};

5. Monitor Memory Usage

Implement monitoring to detect memory exhaustion attempts:

// Log memory usage periodically
setInterval(() => {
  const used = process.memoryUsage();
  console.log({
    heapUsed: Math.round(used.heapUsed / 1024 / 1024) + 'MB',
    heapTotal: Math.round(used.heapTotal / 1024 / 1024) + 'MB'
  });
}, 30000);

Key Takeaways

  • adm-zip 0.5.16 trusts ZIP header values without validation, allowing attackers to trigger excessive memory allocation with crafted files
  • Web services processing user-uploaded ZIPs are directly exploitable without authentication when using vulnerable versions
  • The laliga-fantasy-app's upgrade to adm-zip 0.6.0 adds bounds checking that prevents memory exhaustion attacks
  • Dependency scanning tools like Trivy can automatically detect CVE-2026-39244 in your package-lock.json
  • Defense in depth matters: even with patched libraries, implement file size limits and memory constraints at the application level

How Orbis AppSec Detected This

  • Source: User-uploaded ZIP files processed by the web service
  • Sink: adm-zip library's memory allocation routines when parsing ZIP headers
  • Missing control: No bounds checking on declared uncompressed sizes in adm-zip 0.5.16
  • CWE: CWE-400 (Uncontrolled Resource Consumption)
  • Fix: Upgraded adm-zip from 0.5.16 to 0.6.0, which implements proper memory allocation limits

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-2026-39244 in adm-zip demonstrates how a single vulnerable dependency can expose an entire web service to Denial of Service attacks. The laliga-fantasy-app was at risk of complete service disruption from any user who could upload a crafted ZIP file.

The fix—upgrading from adm-zip 0.5.16 to 0.6.0—was simple to implement but critical for security. This case reinforces the importance of:

  1. Automated dependency scanning in CI/CD pipelines
  2. Prompt patching of known vulnerabilities
  3. Defense in depth with application-level protections

Don't let your fantasy sports app (or any application) become an easy target. Keep your dependencies updated and your memory limits configured.

References

Frequently Asked Questions

What is a Denial of Service via memory exhaustion?

It's an attack where malicious input causes an application to allocate excessive memory, leading to crashes or system unresponsiveness when available memory is exhausted.

How do you prevent memory exhaustion DoS in Node.js?

Use libraries with proper bounds checking, implement file size limits, validate input before processing, set memory limits on Node.js processes, and keep dependencies updated.

What CWE is memory exhaustion DoS?

CWE-400 (Uncontrolled Resource Consumption) covers vulnerabilities where applications don't properly limit resource allocation based on untrusted input.

Is file size validation enough to prevent ZIP-based DoS attacks?

No, because ZIP bombs can have small compressed sizes but expand to massive amounts of data. Libraries must implement decompression ratio limits and memory allocation bounds.

Can static analysis detect memory exhaustion vulnerabilities?

Yes, tools like Trivy can detect known vulnerable library versions, and SAST tools can identify patterns where user input influences memory allocation without bounds checking.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #18

Related Articles

critical

How arbitrary code execution via injected protobuf definition type fields happens in Node.js and how to fix it

A critical arbitrary code execution vulnerability (CVE-2026-41242) was discovered in protobufjs versions prior to 7.5.5 and 8.0.1, allowing attackers to inject malicious code through crafted protobuf definition type fields. The fix upgrades the dependency from the vulnerable version 6.11.4 to 7.5.5, which properly sanitizes type field inputs during protobuf parsing. This vulnerability is especially dangerous because protobufjs is widely used in Node.js applications for serialization, meaning a s

high

How command injection happens in Node.js child_process and how to fix it

A high-severity command injection vulnerability was discovered in `bootstrap.js` at line 34, where the `exec()` function was used to run shell commands constructed from a `folder` variable. By replacing `exec()` with `execFile()` and passing arguments as an array, the fix eliminates the shell interpolation entirely, closing the door on command injection attacks that could have affected all downstream consumers of this Node.js library.

high

How unsafe pickle deserialization happens in NumPy's np.load() and how to fix it

A high-severity arbitrary code execution vulnerability was discovered in `tools/ardy-engine/retarget.py` where `np.load()` was called with `allow_pickle=True`, enabling attackers to embed malicious pickle payloads in `.npz` files. The fix was a single-character change—switching `allow_pickle=True` to `allow_pickle=False`—that eliminates the deserialization attack vector while preserving the file's legitimate array data loading functionality.

high

How SSRF and Credential Leakage via Absolute URLs happens in axios and how to fix it

A high-severity vulnerability (CVE-2025-27152) in axios versions prior to 1.8.2 allowed Server-Side Request Forgery (SSRF) attacks and credential leakage when making HTTP requests with absolute URLs. This vulnerability was fixed by upgrading from axios 1.7.4 to 1.8.2 in both package.json and package-lock.json, eliminating the attack vector that could have exposed authentication tokens and enabled unauthorized server-side requests.

high

How pickle-based arbitrary code execution happens in PyTorch and how to fix it

A high-severity arbitrary code execution vulnerability was discovered in `scripts/export_joyvasa_audio.py` where `torch.load()` was called with `weights_only=False`, allowing any pickle-serialized Python object — including malicious code — to execute during checkpoint loading. The fix switches to `weights_only=True` and explicitly allowlists only the two non-standard classes the checkpoint actually requires: `argparse.Namespace` and `pathlib.PosixPath`. This closes a real code execution path tha

critical

How WebSocket protocol length header abuse happens in Node.js and how to fix it

A critical vulnerability (CVE-2026-54466) in websocket-driver versions prior to 0.7.5 allows attackers to corrupt WebSocket messages by manipulating protocol length headers. This can lead to data integrity issues, denial of service, or potentially arbitrary code execution in affected Node.js applications. The fix involves upgrading the websocket-driver dependency to version 0.7.5.