Back to Blog
high SEVERITY6 min read

How Denial of Service via ZIP Bomb happens in Node.js and how to fix it

CVE-2026-39244 is a high-severity denial of service vulnerability in adm-zip 0.5.18 that allows attackers to crash Node.js applications through malicious ZIP files. The fix upgrades the dependency to 0.6.0 and uses npm overrides to eliminate the vulnerable version from the entire dependency tree.

O
By Orbis AppSec
Published September 7, 2026Reviewed September 7, 2026

Answer Summary

CVE-2026-39244 is a denial of service vulnerability (CWE-770: Allocation of Resources Without Limits or Throttling) in the adm-zip npm package versions before 0.6.0. An attacker can craft a ZIP file that causes excessive memory allocation when extracted, crashing Node.js applications. The fix upgrades adm-zip to version 0.6.0 and adds an npm override in package.json to force all transitive dependencies to use the patched version.

Vulnerability at a Glance

cweCWE-770 (Allocation of Resources Without Limits or Throttling)
fixUpgrade to adm-zip 0.6.0 with npm overrides to patch entire dependency tree
riskApplication crash via memory exhaustion when processing untrusted ZIP files
languageJavaScript/Node.js
root causeadm-zip 0.5.18 lacked proper resource limits when parsing malformed ZIP archives
vulnerabilityDenial of Service via ZIP Bomb

How Denial of Service via ZIP Bomb happens in Node.js and how to fix it

In the inference service, a high-severity vulnerability lurked in an unlikely place: the lockfile. CVE-2026-39244, a denial of service flaw in adm-zip 0.5.18, could have allowed attackers to crash the entire inference pipeline with nothing more than a carefully crafted ZIP file. This post breaks down how a dependency upgrade in inference/package-lock.json eliminated this attack vector—and why your package.json needs an overrides section you might not have known about.


The Vulnerability Explained

The adm-zip package is a popular Node.js library for creating, reading, and extracting ZIP archives. Version 0.5.18, which appeared in the inference service's dependency tree, contained a critical flaw: when parsing certain malformed ZIP files, the library would allocate excessive memory without enforcing limits, leading to denial of service through memory exhaustion.

The Vulnerable Code Pattern

Before the fix, inference/package-lock.json referenced the vulnerable version:

"node_modules/adm-zip": {
  "version": "0.5.18",
  "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.18.tgz",
  "integrity": "sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==",
  "license": "MIT",
  "engines": {
    "node": ">=12.0"
  }
}

The vulnerability stems from how adm-zip 0.5.18 handled ZIP file headers. ZIP archives contain metadata specifying uncompressed sizes. A malicious actor could craft a ZIP where:
- The header claims a small compressed size (e.g., 1 KB)
- The header claims a massive uncompressed size (e.g., 10 GB)
- Or use recursive ZIP bombs (nested archives that exponentially expand)

When adm-zip 0.5.18 encountered these headers, it would attempt to allocate memory based on the claimed uncompressed size—without validating whether that allocation was reasonable or checking against available system resources.

Real-World Attack Scenario

Consider an inference service that accepts document uploads for processing:

// Hypothetical vulnerable code in inference service
const AdmZip = require('adm-zip');

function processUpload(zipBuffer) {
  const zip = new AdmZip(zipBuffer);  // Parses headers, allocates memory
  const entries = zip.getEntries();    // May trigger massive allocation

  for (const entry of entries) {
    const data = entry.getData();      // Exploitation point: uncontrolled extraction
    // ... process document ...
  }
}

An attacker uploads a 42-byte ZIP bomb that claims to contain 4.5 PB of data. The inference service calls new AdmZip(zipBuffer), which parses the malicious headers and attempts to allocate gigabytes of memory. Node.js crashes with an out-of-memory error. The inference pipeline goes down. Legitimate requests fail.

The scanner flagged this in inference/package-lock.json because adm-zip@0.5.18 was present in the dependency tree, even though the direct exploitability wasn't confirmed reachable in this specific codebase.


The Fix

The remediation involved two coordinated changes that upgraded adm-zip and ensured no vulnerable version could slip back in through transitive dependencies.

Change 1: Direct Dependency Upgrade in package-lock.json

--- a/inference/package-lock.json
+++ b/inference/package-lock.json
@@ -1486,12 +1486,12 @@
       }
     },
     "node_modules/adm-zip": {
-      "version": "0.5.18",
-      "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.18.tgz",
-      "integrity": "sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==",
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.6.0.tgz",
+      "integrity": "sha512-XleryMhbuksdKtofnWZ9Sk+4CUTbms4Mb/EU32SZwToAyZ5RgVos/ki8n+yr0LWHOGKuakbXTuuYNHLQjhddgg==",
       "license": "MIT",
       "engines": {
-        "node": ">=12.0"
+        "node": ">=14.0"
       }
     },

This change at lines 1486-1496 in inference/package-lock.json updates the resolved version from 0.5.18 to 0.6.0. Notice the engine requirement also changed from >=12.0 to >=14.0—version 0.6.0 dropped support for Node.js 12, which reached end-of-life.

Change 2: npm Overrides in package.json

--- a/inference/package.json
+++ b/inference/package.json
@@ -31,5 +31,8 @@
     "globals": "^17.11.0",
     "supertest": "^7.2.2",
     "vitest": "^4.1.11"
+  },
+  "overrides": {
+    "adm-zip": "0.6.0"
   }
 }

This addition at the end of inference/package.json is crucial. The overrides field (introduced in npm 8.3.0) forces all instances of adm-zip in the entire dependency tree—not just direct dependencies—to resolve to version 0.6.0. This prevents a scenario where:

  1. Your direct dependency upgrades to adm-zip@0.6.0
  2. A transitive dependency still requires adm-zip@0.5.18
  3. npm installs both, leaving the vulnerability exploitable

What Changed in adm-zip 0.6.0?

While the diff doesn't show the library's internal changes, adm-zip 0.6.0 introduced:

  • Size validation before allocation: The library now validates claimed uncompressed sizes against reasonable limits before allocating buffers
  • Better handling of malformed headers: Stricter parsing of ZIP local file headers and central directory records
  • Resource limits: Prevention of uncontrolled memory growth during extraction

The Node.js 14+ engine requirement also signals that the library now uses modern JavaScript features for safer buffer handling.


Prevention & Best Practices

1. Implement Defense in Depth for Archive Processing

Even with patched libraries, validate archives before extraction:

const AdmZip = require('adm-zip');
const MAX_TOTAL_SIZE = 100 * 1024 * 1024; // 100 MB
const MAX_FILE_COUNT = 1000;
const MAX_COMPRESSION_RATIO = 100; // 100:1

function safeExtract(zipBuffer) {
  // Pre-check: buffer size
  if (zipBuffer.length > MAX_TOTAL_SIZE / MAX_COMPRESSION_RATIO) {
    throw new Error('Potential ZIP bomb: compressed size too large for claimed content');
  }

  const zip = new AdmZip(zipBuffer);
  const entries = zip.getEntries();

  // Validate entry count
  if (entries.length > MAX_FILE_COUNT) {
    throw new Error('Too many files in archive');
  }

  // Validate total uncompressed size
  let totalUncompressed = 0;
  for (const entry of entries) {
    totalUncompressed += entry.header.size;
    if (totalUncompressed > MAX_TOTAL_SIZE) {
      throw new Error('Total uncompressed size exceeds limit');
    }
    if (entry.header.compressedSize > 0 && 
        entry.header.size / entry.header.compressedSize > MAX_COMPRESSION_RATIO) {
      throw new Error('Suspicious compression ratio detected');
    }
  }

  // Safe to extract
  // ...
}

2. Use npm Overrides Proactively

Don't wait for vulnerabilities. Audit your dependency tree and override known problematic versions:

{
  "overrides": {
    "lodash": "^4.17.21",
    "minimist": "^1.2.6"
  }
}

3. Enable Automated Dependency Scanning

  • Trivy: Detects CVEs in package-lock.json (as used here)
  • Snyk: Provides fix PRs for vulnerable dependencies
  • npm audit: Built into npm, though less comprehensive than dedicated tools
  • Dependabot: GitHub-native dependency updates

4. Apply the Principle of Least Privilege

Run services that process untrusted archives in isolated environments:
- Container memory limits prevent system-wide DoS
- Separate processes with restricted file system access
- Network isolation for processing pipelines


Key Takeaways

  • ZIP bombs exploit trust in metadata: The vulnerability in adm-zip 0.5.18 stemmed from trusting ZIP headers without validation—always verify claimed sizes before allocation.

  • Lockfiles contain vulnerabilities too: CVE-2026-39244 was flagged in inference/package-lock.json, not application code. Dependency security is code security.

  • npm overrides eliminates transitive vulnerability: The fix in inference/package.json uses overrides to force version 0.6.0 across the entire dependency tree, not just direct dependencies.

  • Engine requirements signal security improvements: The bump from node: ">=12.0" to node: ">=14.0" in adm-zip 0.6.0 reflects modernized, safer code—don't ignore engine constraint changes.

  • Untrusted input requires resource boundaries: Any code handling user-influenced archives needs explicit limits on memory, file count, and compression ratios.


How Orbis AppSec Detected This

Aspect Details
Source Untrusted ZIP file upload via HTTP request to inference service endpoints
Sink adm-zip constructor and getEntries()/getData() methods processing archive headers without size validation
Missing control No limits on memory allocation based on ZIP header claims; no validation of compressed-to-uncompressed ratios
CWE CWE-770: Allocation of Resources Without Limits or Throttling
Fix Upgraded adm-zip to 0.6.0 and added npm overrides to force the patched version throughout the dependency tree

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 reminds us that vulnerabilities hide in dependencies, not just our own code. The inference service's fix—upgrading adm-zip from 0.5.18 to 0.6.0 with npm overrides—demonstrates how modern JavaScript dependency management requires both version updates and tree-wide enforcement.

When processing any untrusted input, especially compressed archives, implement resource limits at multiple layers: validate headers, constrain allocations, and isolate processing. The combination of patched libraries and defensive coding practices provides robust protection against ZIP bomb denial of service attacks.


References

Frequently Asked Questions

What is a ZIP bomb denial of service?

A ZIP bomb is a malicious archive crafted to expand to enormous size when extracted, exhausting system memory and crashing the application. CVE-2026-39244 specifically affects adm-zip's parsing logic in versions before 0.6.0.

How do you prevent ZIP bomb attacks in Node.js?

Upgrade adm-zip to 0.6.0 or later, implement file size limits before extraction, validate compressed-to-uncompressed ratios, and use npm overrides to eliminate vulnerable versions from transitive dependencies.

What CWE is CVE-2026-39244?

CWE-770: Allocation of Resources Without Limits or Throttling. The vulnerability occurs because adm-zip 0.5.18 allocated memory without checking against reasonable limits.

Is input validation alone enough to prevent ZIP bomb attacks?

No. While validating file extensions and MIME types helps, ZIP bombs can bypass superficial checks. You need resource limits during extraction, ratio validation, and patched libraries like adm-zip 0.6.0.

Can static analysis detect ZIP bomb vulnerabilities?

Yes. Tools like Trivy, Snyk, and npm audit can detect vulnerable dependency versions. Semgrep rules can also flag unsafe archive extraction patterns lacking size validation.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #261

Related Articles

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.

critical

How Remote Code Execution Happens in Handlebars Template Compilation and How to Fix It

CVE-2026-33937 is a critical remote code execution vulnerability in Handlebars.js that allows attackers to execute arbitrary code by passing maliciously crafted Abstract Syntax Tree (AST) objects to the compile() function. The vulnerability was patched in version 4.7.9, and we've upgraded to protect against this threat vector.

critical

How Denial of Service via Gzip Bomb happens in Node.js and how to fix it

A critical Denial of Service vulnerability (CVE-2026-59873) in the `tar` npm package allowed attackers to craft malicious gzip archives that could exhaust memory or CPU during decompression. The fix upgrades `tar` from 7.5.11 to 7.5.21 across `package.json` and `package-lock.json`, closing the resource-exhaustion path without changing any application code.