Zip Slip in Feathersjs with Cockroachdb
Zip Slip in Feathersjs with Cockroachdb — 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 sanitization. In a Feathersjs application using Cockroachdb, this typically manifests in services that handle file uploads, backups, or export operations where a filename or path parameter is stored in Cockroachdb and later used to read or write files.
Feathersjs services often rely on hooks to process data before it is stored in Cockroachdb. If a hook accepts a user-provided path or archive filename and concatenates it directly to a base directory, an attacker can supply a specially crafted filename containing sequences like ../ to traverse directories. Because Cockroachdb is used as the persistence layer, the malicious path may be stored and later used by file system operations, enabling unauthorized access or overwriting of files outside the intended directory.
The interaction between Feathersjs hooks and Cockroachdb can inadvertently preserve malicious path data. For example, a file metadata record containing a relative path might be saved to Cockroachdb via a Feathersjs service, and later a background job uses that path to extract an archive. If the path is not validated or normalized before use, the traversal is possible. Additionally, if the Feathersjs application exposes administrative endpoints that query Cockroachdb for file-related records and serve files based on stored paths, the vulnerability can be exploited without direct user interaction with the file system.
Real-world attack patterns include storing a path like ../../../etc/passwd in a Cockroachdb record via a Feathersjs create call, then later using that path in a file-read operation. This can lead to sensitive data exposure or unauthorized file modification. The use of Cockroachdb does not introduce the vulnerability, but it can act as a persistent store that enables the attack across sessions or between different parts of the application.
To detect this during a scan, middleBrick tests unauthenticated endpoints that accept file or path inputs, checks whether user data is persisted in Cockroachdb, and verifies whether stored paths are later used in file operations. The scanner does not modify data but identifies whether user-controlled paths can reach file system interactions through the Feathersjs service layer and Cockroachdb storage.
Cockroachdb-Specific Remediation in Feathersjs — concrete code fixes
Remediation focuses on validating and sanitizing paths before they are stored in Cockroachdb or used in file operations. Avoid direct concatenation of user input into file paths. Use a secure base directory and resolve paths to ensure they remain within allowed locations.
Example of a vulnerable Feathersjs service that stores a user-supplied path in Cockroachdb and later uses it:
// Vulnerable code example
app.service('exports').hooks({
before: {
create: async context => {
const { filePath } = context.data; // user-controlled
context.data.storedPath = filePath; // stored in Cockroachdb via Feathersjs
return context;
}
},
after: {
create: async context => {
const { storedPath } = context.result;
fs.readFileSync(storedPath); // unsafe use
return context;
}
}
});
Secure version using path normalization and a controlled base directory:
const path = require('path');
const BASE_DIR = '/safe/export';
app.service('exports').hooks({
before: {
create: async context => {
const userPath = context.data.filePath;
const safePath = path.normalize(userPath).replace(/^(\/|\.\.)/, '');
const resolved = path.resolve(BASE_DIR, safePath);
if (!resolved.startsWith(BASE_DIR)) {
throw new Error('Invalid path');
}
context.data.storedPath = resolved; // safe path stored in Cockroachdb
return context;
}
},
after: {
create: async context => {
const { storedPath } = context.result;
fs.readFileSync(storedPath); // safe use
return context;
}
}
});
When using Cockroachdb with an ORM or query builder in Feathersjs, ensure that path fields are validated before persistence. For example, using a validation hook that checks for directory traversal sequences:
app.service('files').hooks({
before: {
create: [context => {
const { archivePath } = context.data;
if (archivePath.includes('..') || archivePath.includes('~')) {
throw new Error('Path traversal not allowed');
}
context.data.archivePath = path.resolve(archivePath);
return context;
}]
}
});
Additionally, when serving files generated or referenced from Cockroachdb, always construct the path server-side using a known base directory and avoid returning raw user input to the client for path resolution. This prevents stored malicious paths from being used in subsequent requests.