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
•Technically reviewed by Anupam Mediratta•Published September 7, 2026•Reviewed 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.


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.


Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #261

Related Articles

critical

Lampa Desktop Auto-Update Heuristic Bypass: Execution of Unverified

Lampa Desktop's auto-update mechanism downloaded JavaScript and CSS from `raw.githubusercontent.com` using only heuristic validation—file size thresholds and string pattern matching—that attackers could trivially satisfy. The fix introduces cryptographic integrity verification by cross-referencing Git blob hashes from the GitHub Contents API, ensuring downloaded code matches the repository's authoritative state before execution.

high

adm-zip 0.6.0 Preserves SUID Bits From ZIPs: CVE-2026-102282

The `adm-zip` dependency resolved to 0.6.0 in this project's dependency tree, a version affected by CVE-2026-102282: during extraction it applies the Unix permission bits stored in each ZIP entry's external file attributes verbatim, including the setuid (`04000`), setgid (`02000`), and sticky bits. An attacker who controls an archive passed to `extractAllTo()` or `extractEntryTo()` can therefore have the extractor create a setuid binary owned by whatever user the extraction process runs as. The

high

requestInput() Type Confusion: NaN and Object Bypass in JavaScript

The `requestInput()` utility function lacked validation on its `type` parameter and failed to handle `NaN` results from float conversions, creating a type confusion weakness. An attacker could supply malformed inputs that propagate unhandled `NaN` values or unexpected object types through the type system. The fix adds explicit guards against `NaN` type parameters and rejects non-primitive type values.

critical

No Rate Limit on /api/uploads/presign Enables DoS

The `/api/uploads/presign` endpoint accepted unlimited concurrent requests to generate storage presigned URLs, giving an attacker a free lever to exhaust storage-provider quotas and server resources. The fix adds an `express-rate-limit` middleware capping each client to 30 requests per minute on that route.

high

CVE-2026-54673: builder-util-runtime Leaks Auth Headers on Redirect

electron-updater and electron-builder rely on builder-util-runtime to fetch update manifests and artifacts over HTTP. A flaw in that shared HTTP executor allowed credential headers attached to the original update-feed request to be re-sent after a redirect, exposing them to any host the redirect pointed to. The project fixes this by upgrading builder-util-runtime to 9.7.0 and collapsing a duplicate, older copy of the package that electron-updater had pinned on its own.

high

image-size 1.2.1 DoS: Zero-Valued Dimensions in Image Buffer Parser

A high-severity denial-of-service vulnerability in image-size 1.2.1 allows attackers to crash Node.js services using malicious image buffers with zero-valued dimensions. The fix removes the vulnerable `queue` dependency and tightens dimension validation in version 2.0.3.