HIGH zip slipexpress

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 true parameters 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 false to 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.

Frequently Asked Questions

How does Zip Slip differ from other path traversal vulnerabilities in Express?
Zip Slip specifically exploits archive extraction where malicious paths are embedded within compressed files, while traditional path traversal attacks manipulate URL parameters or file paths in real-time requests. Zip Slip requires processing the archive contents first, making it a supply-chain vulnerability that can hide malicious intent within seemingly legitimate uploads.
Can Zip Slip lead to remote code execution in Express applications?
Yes, Zip Slip can lead to remote code execution if an attacker overwrites critical files like server configuration, application code, or executable scripts. For example, replacing a Node.js module file or configuration file that gets loaded at runtime could allow an attacker to inject malicious code that executes with the application's privileges.