Zip Slip in Express
How Zip Slip Manifests in Express
Zip Slip vulnerabilities in Express applications typically occur when file upload endpoints accept compressed archives and extract them without proper path validation. The vulnerability allows attackers to overwrite arbitrary files on the server by crafting archive entries with path traversal sequences like ../../ or absolute paths.
In Express, this commonly appears in multipart form handlers where users can upload ZIP files. Consider this vulnerable Express endpoint:
const express = require('express');
const multer = require('multer');
const AdmZip = require('adm-zip');
const fs = require('fs');
const app = express();
const upload = multer({ dest: 'uploads/' });
app.post('/upload-archive', upload.single('archive'), (req, res) => {
const zip = new AdmZip(req.file.path);
zip.extractAllTo('public/', true); // Vulnerable: no path validation
res.send('Archive extracted successfully');
});
The critical vulnerability here is extractAllTo('public/', true) — the second parameter true allows overwriting existing files, and there's no validation of entry paths. An attacker could upload a ZIP containing:
../../config/database.json
../../server.js
/etc/passwd
When extracted, these entries would overwrite critical files outside the intended directory. Another common pattern in Express applications is using unzip npm package:
const unzip = require('unzip');
const fs = require('fs');
app.post('/upload-zip', upload.single('zipfile'), (req, res) => {
const writeStream = fs.createWriteStream('public/');
req.pipe(unzip.Extract({ path: 'public/' })); // Still vulnerable without validation
res.send('Extraction started');
});
Both patterns fail to sanitize file paths, making them susceptible to Zip Slip attacks that can lead to remote code execution if the attacker overwrites executable files or configuration files that are later loaded by the application.
Express-Specific Detection
Detecting Zip Slip vulnerabilities in Express applications requires examining both the code and runtime behavior. In the code review phase, look for these specific patterns:
- File extraction without path validation in multipart upload handlers
- Use of
adm-zip,unzip, or similar extraction libraries without sanitization - Hardcoded
trueparameters that allow overwriting files - Path concatenation without normalization or validation
middleBrick's API security scanner can automatically detect these vulnerabilities by analyzing your Express endpoints. When you scan an Express application with middleBrick, it examines the runtime behavior of your file upload endpoints and tests them with crafted payloads.
For example, middleBrick would test your /upload-archive endpoint by uploading a ZIP file containing:
test_../../etc/passwd
The scanner then verifies if the extraction process allows writing outside the intended directory. middleBrick's black-box scanning approach means you don't need to provide source code — it tests the actual running endpoint as an attacker would.
Beyond automated scanning, you can use Express middleware to add security checks. Here's a middleware that validates ZIP contents before extraction:
const validateZipEntries = (req, res, next) => {
if (!req.file || req.file.mimetype !== 'application/zip') {
return next();
}
const zip = new AdmZip(req.file.path);
const entries = zip.getEntries();
for (const entry of entries) {
const entryName = entry.entryName;
if (entryName.includes('..') || entryName.startsWith('/') || entryName.startsWith('\')) {
return res.status(400).send('Invalid file path in archive');
}
}
next();
};
app.post('/upload-archive', upload.single('archive'), validateZipEntries, (req, res) => {
const zip = new AdmZip(req.file.path);
zip.extractAllTo('public/', false); // false prevents overwriting
res.send('Archive extracted safely');
});
This middleware catches malicious archives before extraction occurs, preventing Zip Slip attacks at the Express application layer.
Express-Specific Remediation
Remediating Zip Slip in Express requires a defense-in-depth approach. The most critical fix is implementing strict path validation before any file extraction occurs. Here's a comprehensive Express middleware solution:
const path = require('path');
const AdmZip = require('adm-zip');
const safeExtractZip = (zip, targetDir) => {
const entries = zip.getEntries();
for (const entry of entries) {
const entryName = entry.entryName.replace(/\/g, '/'); // Normalize path separators
const resolvedPath = path.resolve(targetDir, entryName);
// Ensure the resolved path is within the target directory
if (!resolvedPath.startsWith(path.resolve(targetDir) + path.sep)) {
throw new Error(`Entry ${entryName} is outside the target directory`);
}
// Check for dangerous patterns
if (entryName.includes('..') || entryName.startsWith('/') || entryName.startsWith('\')) {
throw new Error(`Entry ${entryName} contains invalid path characters`);
}
// Optional: check for executable files if not needed
if (entryName.match(//(exe|bat|sh|js|py|rb|php)$/i)) {
throw new Error(`Entry ${entryName} is an executable file`);
}
}
zip.extractAllTo(targetDir, false); // false prevents overwriting existing files
};
app.post('/upload-archive', upload.single('archive'), (req, res) => {
try {
const zip = new AdmZip(req.file.path);
safeExtractZip(zip, 'public/');
res.send('Archive extracted safely');
} catch (error) {
console.error('Zip extraction error:', error.message);
res.status(400).send('Invalid archive content');
}
});
This implementation validates every entry in the ZIP archive before extraction. The key security checks are:
- Path normalization and resolution to prevent traversal
- Prefix validation ensuring all paths stay within the target directory
- Detection of path traversal patterns like
.. - Optional filtering of executable file types
- Setting overwrite to
falseto prevent accidental file replacement
For Express applications using TypeScript or modern JavaScript, you can enhance this with additional type safety and error handling. Also consider implementing rate limiting on file upload endpoints to prevent abuse, and always scan uploaded files with antivirus software before processing.
middleBrick can help verify your remediation by continuously scanning your fixed endpoints. After implementing these fixes, run middleBrick to ensure the Zip Slip vulnerability is resolved and monitor your API security score in the dashboard. The scanner will attempt the same malicious payloads to confirm they're properly blocked, giving you confidence that your Express application is protected against this specific attack vector.