HIGH zip slipexpressbearer tokens

Zip Slip in Express with Bearer Tokens

Zip Slip in Express with Bearer Tokens — how this specific combination creates or exposes the vulnerability

Zip Slip is a path traversal vulnerability that occurs when an application constructs file paths using user-supplied input without proper validation. In an Express API that uses Bearer Tokens for authentication, the combination of unrestricted path resolution and bearer-based authorization can allow an authenticated attacker to traverse directories and access or overwrite files on the server. A typical Express route might extract a filename or archive destination from request parameters and then directly join it with a base directory. If the request includes a bearer token in the Authorization header and the token is accepted without additional validation of the intended file path, an attacker can supply a crafted payload such as ../../../etc/passwd inside an archive or as a path parameter, causing the resolved location to escape the intended directory.

In this scenario, bearer tokens protect the endpoint at the authentication/authorization layer but do not mitigate path traversal risks within the business logic. The token confirms identity and scope, yet if the server trusts the submitted path, an authenticated user can read arbitrary files or write outside allowed directories when extracting uploaded archives. For example, an Express route that extracts a user-uplied zip and uses zip.extractAll(path) without sanitizing entry names can be exploited via a malicious archive containing files with paths like ../../secrets/config.json. Because the API uses bearer tokens, the request includes a valid token and passes any simplistic auth checks, but the lack of path canonicalization and validation enables unauthorized file system access.

Moreover, if the Express application exposes endpoints that both validate bearer tokens and handle file operations, an attacker may probe for insecure extraction logic while authenticated. The presence of a bearer token may lead developers to assume the endpoint is safe, but if path traversal is possible, the attacker can read sensitive configuration files, logs, or source code. This highlights that authentication and authorization (bearer token checks) are separate from input validation and path sanitization; failing to secure file paths in an authenticated context still results in a critical security flaw.

Bearer Tokens-Specific Remediation in Express — concrete code fixes

To remediate Zip Slip in Express when using Bearer Tokens, focus on secure path handling and strict validation rather than relying on token-based authorization alone. Always resolve file paths to their canonical absolute forms and enforce that they remain within a designated base directory. Below are concrete code examples demonstrating secure Express routes with bearer token validation and safe file extraction.

1) Secure path resolution with Bearer Token validation

Use path.resolve() and path.relative() to ensure extracted or constructed paths remain inside an allowed directory. Combine this with Bearer Token verification using a middleware that attaches user context to the request.

const express = require('express');
const path = require('path');
const fs = require('fs');
const app = express();

// Middleware to validate Bearer token and attach user
function validateBearerToken(req, res, next) {
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  const token = authHeader.slice(7);
  // Validate token (e.g., verify JWT or check against a store)
  if (!isValidToken(token)) {
    return res.status(403).json({ error: 'Forbidden' });
  }
  req.user = { token }; // attach user context for logging/auditing
  next();
}

function isValidToken(token) {
  // Replace with real token validation logic
  return token && token.length > 10;
}

app.post('/files/extract', validateBearerToken, (req, res) => {
  const { filename } = req.body; // e.g., provided by the user
  const baseDir = path.resolve(__dirname, 'uploads');
  const destPath = path.resolve(baseDir, filename);

  if (!destPath.startsWith(baseDir)) {
    return res.status(400).json({ error: 'Invalid path: traversal detected' });
  }

  // Proceed with safe extraction using a library that prevents path traversal
  // e.g., const extract = require('unzipper');
  // fs.createReadStream(archivePath).pipe(extract.Extract({ path: destPath }));
  res.json({ message: 'Extraction path validated', path: destPath });
});

app.listen(3000, () => console.log('Server running on port 3000'));

2) Secure archive extraction with canonicalization

When handling uploaded archives, use a library that sanitizes entry names and always compute the final path using canonicalization. Do not rely on the archive’s internal paths alone.

const express = require('express');
const path = require('path');
const fs = require('fs');
const unzipper = require('unzipper');
const app = express();

app.use(express.json());

function validateBearerToken(req, res, next) {
  const auth = req.headers.authorization;
  if (!auth || !auth.startsWith('Bearer ')) return res.status(401).json({ error: 'Unauthorized' });
  const token = auth.substring(7);
  if (!isValidToken(token)) return res.status(403).json({ error: 'Forbidden' });
  req.user = { id: 'user123' };
  next();
}

function isValidToken(token) {
  return token === 'valid_test_token_example';
}

app.post('/upload/extract', validateBearerToken, async (req, res) => {
  const archivePath = path.resolve(__dirname, 'uploads', req.body.archiveName);
  const extractDir = path.resolve(__dirname, 'extracted');

  await fs.createReadStream(archivePath)
    .pipe(unzipper.Parse())
    .on('entry', (entry) => {
      const safePath = path.normalize(entry.path).replace(/^(\/|\.\.)/, '');
      const outPath = path.join(extractDir, safePath);
      if (!outPath.startsWith(extractDir)) {
        entry.autodrain();
        throw new Error('Path traversal detected in archive');
      }
      entry.pipe(fs.createWriteStream(outPath));
    })
    .on('close', () => res.json({ message: 'Extraction completed safely' }));
});

app.listen(3000, () => console.log('Server running on port 3000'));

These examples show how to integrate Bearer Token validation with secure path handling. The key remediation steps are: validate and sanitize all user-supplied paths, canonicalize destinations, and enforce strict base-directory containment regardless of authentication status.

Frequently Asked Questions

Does using Bearer Tokens alone prevent Zip Slip in Express APIs?
No. Bearer Tokens provide authentication and authorization but do not prevent path traversal. You must validate and sanitize file paths and enforce directory boundaries independently of token checks.
What additional practices help prevent Zip Slip in Express when bearer tokens are used?
Use libraries that sanitize archive entries, resolve paths with path.resolve, and assert path containment with path.relative or path.startsWith. Avoid trusting entry paths from archives, and apply the same validation to authenticated and unauthenticated contexts.