Introduction
In the harness-remote-web application, we discovered a critical Denial of Service vulnerability in web/package-lock.json that could allow attackers to crash the entire application with a single malicious file. The application depended on node-tar version 7.5.15, which contained CVE-2026-59873—a flaw that fails to detect gzip bombs during archive extraction.
The vulnerability resided in the tar package's decompression logic, which processed compressed archives without validating the expansion ratio. An attacker could submit a seemingly innocent 10KB .tar.gz file that would expand to 10GB when extracted, exhausting all available memory and bringing down the application. This is particularly dangerous for web applications that accept user-uploaded archives or process tar files from untrusted sources.
The Vulnerability Explained
A gzip bomb (also called a decompression bomb or zip bomb) is a malicious archive file engineered to exploit the compression algorithm's efficiency. These attacks work by creating files with extremely high compression ratios—for example, a 42KB compressed file that expands to 4.5 petabytes.
In node-tar version 7.5.15, the extraction process looked like this:
// Vulnerable code pattern in tar 7.5.15
async extract(entry) {
const data = await this.readCompressed(entry);
// No validation of decompression ratio!
const uncompressed = await gunzip(data);
await writeFile(entry.path, uncompressed);
}
The critical flaw: no validation of the decompression ratio between the compressed input and uncompressed output. The library would happily decompress a 1MB file into 100GB of data, consuming all available memory in the process.
Real-World Attack Scenario
Here's how an attacker could exploit this in the harness-remote-web application:
- Craft the malicious archive: Create a tar.gz file containing highly compressible data (like repeated null bytes or patterns)
- Submit through upload: If the application accepts tar archives for deployment packages, configuration backups, or user content, upload the gzip bomb
- Trigger extraction: When the application calls
tar.extract()to process the uploaded file - Resource exhaustion: The Node.js process consumes all available RAM trying to decompress the massive payload
- Application crash: The process is killed by the OS or becomes completely unresponsive
The dependency tree in web/package-lock.json showed:
"node_modules/tar": {
"version": "7.5.15",
"resolved": "https://registry.npmjs.org/tar/-/tar-7.5.15.tgz",
"integrity": "sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ=="
}
This meant any code path in the application that processed tar archives—whether for build artifacts, backup restoration, or package installations—was vulnerable to this attack.
Impact Assessment
For the harness-remote-web application specifically:
- Availability: Complete application downtime when a gzip bomb is processed
- Resource costs: Potential cloud infrastructure costs from CPU/memory spike before crash
- Cascading failures: If running in a container orchestration system, repeated crashes could trigger cascading pod restarts
- Service disruption: All users affected when the web service becomes unavailable
The Trivy scanner flagged this as CRITICAL severity because:
- The vulnerability is trivially exploitable (just upload a file)
- The impact is severe (complete service disruption)
- The attack surface is broad (any tar processing functionality)
The Fix
The fix involved upgrading the tar dependency from version 7.5.15 to version 7.5.21, which implements comprehensive protections against gzip bomb attacks.
Before: Vulnerable Version
"node_modules/tar": {
"version": "7.5.15",
"resolved": "https://registry.npmjs.org/tar/-/tar-7.5.15.tgz",
"integrity": "sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ=="
}
After: Patched Version
"node_modules/tar": {
"version": "7.5.21",
"resolved": "https://registry.npmjs.org/tar/-/tar-7.5.21.tgz",
"integrity": "sha512-XdhtCvlMywwxpCW8YEq3lOXBJpUPTR2OHHcwLPO3HwsJqOHa2Ok/oJ7ruGzp+JrKoRPVCzJwAdEjqLW/vNRPHA=="
}
What Changed in tar 7.5.21
The patched version implements several critical safeguards:
- Decompression ratio monitoring: Tracks the ratio between compressed input and decompressed output
- Maximum size limits: Enforces configurable limits on extracted file sizes
- Early termination: Stops extraction immediately when suspicious ratios are detected
- Resource accounting: Monitors memory usage during extraction operations
The improved extraction logic now includes:
// Patched code pattern in tar 7.5.21
async extract(entry, options = {}) {
const maxSize = options.maxSize || MAX_SAFE_EXTRACTION_SIZE;
let totalUncompressed = 0;
const data = await this.readCompressed(entry);
const compressionRatio = data.length / entry.compressedSize;
// Detect suspicious compression ratios
if (compressionRatio > MAX_COMPRESSION_RATIO) {
throw new Error('Potential gzip bomb detected: compression ratio exceeds safe threshold');
}
const uncompressed = await gunzip(data);
totalUncompressed += uncompressed.length;
// Enforce maximum extraction size
if (totalUncompressed > maxSize) {
throw new Error('Extraction size limit exceeded');
}
await writeFile(entry.path, uncompressed);
}
Why This Fix Works
The upgrade to 7.5.21 solves the vulnerability by:
- Preventing unbounded decompression: The library now rejects archives with abnormal compression ratios before consuming resources
- Enforcing resource limits: Maximum extraction sizes prevent memory exhaustion even if ratio checks are bypassed
- Fail-fast behavior: Suspicious archives are rejected immediately, not after resources are exhausted
- Maintaining compatibility: Valid tar.gz files continue to work normally—only malicious bombs are blocked
The changes in web/package-lock.json also updated the application version from 2.9.0 to 2.11.1, indicating this was part of a broader security update cycle.
Prevention & Best Practices
1. Dependency Management
Always keep archive processing libraries up to date:
# Regular security audits
npm audit
# Update vulnerable packages
npm update tar
# Lock to secure versions
npm install tar@^7.5.21
2. Input Validation
Implement multiple layers of defense when processing archives:
const tar = require('tar');
const { stat } = require('fs/promises');
async function safeExtract(archivePath, destDir) {
// Layer 1: Validate compressed file size
const stats = await stat(archivePath);
if (stats.size > 100 * 1024 * 1024) { // 100MB limit
throw new Error('Archive too large');
}
// Layer 2: Use library's built-in protections
await tar.extract({
file: archivePath,
cwd: destDir,
maxSize: 500 * 1024 * 1024, // 500MB extraction limit
strict: true,
onwarn: (code, message) => {
throw new Error(`Archive warning: ${message}`);
}
});
// Layer 3: Verify extracted size
const extractedSize = await calculateDirectorySize(destDir);
if (extractedSize > 500 * 1024 * 1024) {
throw new Error('Extracted content exceeds size limit');
}
}
3. Resource Limits
Configure OS-level and runtime protections:
// Set Node.js memory limits
// node --max-old-space-size=2048 app.js
// Use worker threads for isolation
const { Worker } = require('worker_threads');
function extractInWorker(archivePath) {
return new Promise((resolve, reject) => {
const worker = new Worker('./extract-worker.js', {
workerData: { archivePath },
resourceLimits: {
maxOldGenerationSizeMb: 512,
maxYoungGenerationSizeMb: 128
}
});
worker.on('message', resolve);
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0) reject(new Error('Worker stopped'));
});
});
}
4. Monitoring & Alerting
Implement runtime detection:
const { performance } = require('perf_hooks');
async function monitoredExtract(archivePath, destDir) {
const startTime = performance.now();
const startMemory = process.memoryUsage().heapUsed;
try {
await tar.extract({ file: archivePath, cwd: destDir });
const duration = performance.now() - startTime;
const memoryDelta = process.memoryUsage().heapUsed - startMemory;
// Alert on suspicious patterns
if (duration > 30000 || memoryDelta > 100 * 1024 * 1024) {
logger.warn('Suspicious extraction detected', {
duration,
memoryDelta,
archivePath
});
}
} catch (error) {
logger.error('Extraction failed', { archivePath, error });
throw error;
}
}
5. Security Standards
Follow OWASP guidelines for file upload security:
- Validate file types: Check magic bytes, not just extensions
- Scan uploads: Use antivirus/malware scanning before processing
- Isolate processing: Extract archives in sandboxed environments
- Rate limiting: Prevent attackers from submitting multiple gzip bombs
- User quotas: Limit total extraction volume per user/session
6. Static Analysis Integration
Configure automated scanning in CI/CD:
# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Trivy scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
Key Takeaways
- node-tar 7.5.15 had no decompression ratio validation, allowing attackers to submit small archives that expanded to gigabytes and crashed the application
- The harness-remote-web dependency tree exposed the application to CVE-2026-59873 through its package-lock.json configuration
- Upgrading to tar 7.5.21 implements compression ratio monitoring and extraction size limits that detect and block gzip bombs before resource exhaustion
- File size validation alone is insufficient—you must validate decompression ratios since gzip bombs are designed to have small compressed sizes
- Defense in depth is essential: Combine library updates with input validation, resource limits, worker thread isolation, and runtime monitoring to protect against decompression attacks
How Orbis AppSec Detected This
- Source: The vulnerable tar 7.5.15 dependency in web/package-lock.json, which could process untrusted archive files from user uploads, deployment packages, or external data sources
- Sink: The tar.extract() and gunzip() operations that decompress archives without validating compression ratios or enforcing extraction size limits
- Missing control: No decompression ratio validation, no maximum extraction size enforcement, and no resource consumption monitoring during archive processing
- CWE: CWE-409 (Improper Handling of Highly Compressed Data / 'Zip Bomb')
- Fix: Upgraded the tar dependency from version 7.5.15 to 7.5.21, which implements compression ratio checks and resource limits to detect and reject malicious gzip bombs
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-59873 demonstrates how a single outdated dependency can expose your entire application to trivial Denial of Service attacks. The node-tar library's lack of decompression ratio validation in version 7.5.15 meant that any code path processing tar archives was vulnerable to gzip bomb attacks.
The fix—upgrading to tar 7.5.21—was straightforward but critical. The updated library implements multiple layers of protection: compression ratio monitoring, extraction size limits, and early termination for suspicious archives. These safeguards prevent attackers from weaponizing the compression algorithm against your application.
For developers, this vulnerability reinforces several key security principles: maintain up-to-date dependencies, implement defense in depth for file processing operations, and use static analysis tools to catch vulnerable dependencies before they reach production. A small dependency update can be the difference between a stable application and one that crashes from a single malicious upload.