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.