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

medium

How Insufficient Password Hashing Cost Factor Happens in Node.js and How to Fix It

A bcrypt password hashing implementation in the User.js model was using a cost factor of 10, which falls below OWASP's 2024 recommendation of 12 for applications handling sensitive data. This fix upgrades the salt rounds from 10 to 12, increasing the computational work required to crack passwords by approximately 4x, significantly improving protection against brute-force attacks on this e-commerce platform.

high

How Arbitrary Code Execution via Template Imports Happens in JavaScript (lodash) and How to Fix It

A high-severity arbitrary code execution vulnerability (CVE-2026-4800) was discovered in lodash's template function, specifically in how it handles the `imports` option with untrusted input. The fix upgrades lodash from version 4.17.21 to 4.18.0 in the project's `package.json` and `yarn.lock`, eliminating the attack surface where crafted template imports could execute arbitrary code on the server.

critical

How Server-Side Request Forgery (SSRF) happens in Node.js IP address parsing and how to fix it

A critical SSRF vulnerability (CVE-2026-69192) was discovered in the ip-address npm package version 10.2.0, which could allow attackers to bypass IP address validation and access internal services. The fix upgrades the dependency to version 10.3.1, which properly handles edge cases in IP address parsing that previously allowed trust-boundary bypasses.

critical

How Sensitive Data Exposure happens in Python web applications and how to fix it

A critical sensitive data exposure vulnerability was discovered in `nodes/google_gemini.py` where the Google Gemini API key was returned in plaintext through a web endpoint. The fix masks the token in API responses, preventing credential theft from any client that queries the token endpoint. This protects downstream users of this Node.js library from unauthorized access to their Google Gemini services.

high

How Authentication Bypass happens in Next.js App Router with Turbopack and how to fix it

A critical authentication bypass vulnerability (CVE-2026-64642) was discovered in Next.js versions prior to 16.2.11, specifically affecting App Router applications using Turbopack with a single locale configuration. This vulnerability allowed attackers to bypass middleware and proxy protections, potentially gaining unauthorized access to protected routes and resources that should have been secured by authentication checks.

critical

How SQL Injection Happens in CSV-to-SQL Converters and How to Fix It

A critical SQL injection vulnerability was discovered in the `csv2sql()` function in `src/data/converter/csv.js`, where CSV data and table names were directly interpolated into SQL INSERT statements without sanitization. The fix implements input validation through identifier sanitization and proper value escaping, eliminating the attack surface while preserving legitimate functionality.