Zip Slip in Feathersjs with Basic Auth
Zip Slip in Feathersjs with Basic Auth — 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 unsanitized user input. In Feathersjs, a common pattern is to use a hook that processes uploads or file-related parameters. When Basic Auth is used for access control, developers may assume that authentication alone constrains what a user can do, but authentication does not sanitize or validate file paths. This misalignment creates an exposure: an authenticated request (with valid Basic Auth credentials) can supply a malicious path such as ../../../etc/passwd or a crafted archive containing path traversal sequences, and Feathersjs may pass that input directly to file system operations without normalization or validation.
Consider a Feathersjs service that handles file extraction. A client sends a POST with an archive in the body and includes Basic Auth headers. If the service reads the archive name or extracts entries using user-controlled metadata without resolving path segments, an attacker can craft a filename that traverses directories. Because the request is authenticated via Basic Auth, the server may trust the context and proceed with file operations, inadvertently allowing writes outside the intended directory. The vulnerability is not in Basic Auth itself, but in how Feathersjs code handles paths after authentication—specifically, the lack of path canonicalization and strict allowlist checks on destination directories.
OpenAPI/Swagger specs for Feathersjs services often define request bodies and parameters without strict schema constraints on path fields, which means runtime validation is essential. A malicious actor can probe the unauthenticated attack surface—even when Basic Auth is present—by sending crafted requests that include traversal patterns. If the Feathersjs application uses middleware that concatenates user input into file paths (e.g., path.join(base, req.body.filename)) without resolving .. sequences, the resulting path can escape the base directory. This becomes a practical attack vector when combined with features like file uploads or archive extraction, common in Feathersjs apps that integrate storage plugins.
Notably, middleBrick does not perform source code analysis or claim to fix these issues; it detects indicators such as unusual file paths in runtime scans and provides remediation guidance. Findings may map to OWASP API Top 10 A01:2023 Broken Object Level Authorization and A05:2023 Security Misconfiguration, highlighting the importance of validating and sanitizing inputs even when authentication is enforced.
Basic Auth-Specific Remediation in Feathersjs — concrete code fixes
To remediate Zip Slip in Feathersjs when using Basic Auth, ensure that all file paths are validated and resolved against a strict allowlist of permitted directories. Do not rely on authentication to enforce path constraints. Use Node.js path utilities to canonicalize and check paths before any file system operation.
Example of insecure code:
const path = require('path');
app.use('/uploads', {
async create(data, params) {
const { filename, archive } = data;
const dest = path.join(__dirname, 'public/uploads', filename);
// Unsafe: filename may contain '../' and traverse directories
await extractArchive(archive, dest);
return { message: 'Extracted' };
}
});
Secure remediation with path validation:
const path = require('path');
const allowedBase = path.resolve(__dirname, 'public/uploads');
app.use('/uploads', {
async create(data, params) {
const { filename, archive } = data;
const target = path.resolve(allowedBase, filename);
if (!target.startsWith(allowedBase)) {
throw new Error('Invalid path: traversal detected');
}
await extractArchive(archive, target);
return { message: 'Extracted' };
}
});
When using Basic Auth, incorporate an authentication hook that enforces scope or role constraints, but still validate paths independently. Example of a Feathers hook that checks credentials and sanitizes input:
const { AuthenticationError } = require('@feathersjs/errors');
const bcrypt = require('bcryptjs');
const path = require('path');
const allowedBase = path.resolve(__dirname, 'public/uploads');
const verifyAuth = async (context) => {
const { username, password } = context.params.headers;
if (!username || !password) {
throw new AuthenticationError('Missing credentials');
}
// Example user validation (replace with your user service lookup)
const user = await context.app.service('users').get(username);
const valid = await bcrypt.compare(password, user.passwordHash);
if (!valid) {
throw new AuthenticationError('Invalid credentials');
}
return context;
};
const pathValidationHook = (context) => {
const { filename } = context.data;
const target = path.resolve(allowedBase, filename);
if (!target.startsWith(allowedBase)) {
throw new Error('Invalid path: traversal detected');
}
context.params.safeDest = target;
return context;
};
app.hooks({
before: {
all: [verifyAuth],
create: [pathValidationHook]
}
});
These examples show how to integrate authentication checks with strict path resolution. Even when Basic Auth is present, always resolve and validate file paths, and avoid concatenating user input directly into filesystem operations. middleBrick can help identify missing validations in runtime scans, and its dashboard and CLI allow you to track and manage API security over time.