Symlink Attack in Feathersjs
How Symlink Attack Manifests in Feathersjs
Symlink attacks in Feathersjs applications typically occur when user-controlled input is used to construct file paths for operations like file uploads, static asset serving, or database file access. The vulnerability arises when an attacker can create or manipulate symbolic links to access files outside the intended directory structure.
In Feathersjs, this often manifests through the multer middleware for file uploads or when using fs operations with dynamic paths. A common scenario involves allowing users to specify filenames or upload to custom directories without proper validation. For example:
const uploadService = feathers-multer({ dest: '/uploads' });
// Vulnerable: user controls the filename
app.post('/upload', uploadService.single('file'), async (req, res) => {
const filePath = `/uploads/${req.body.filename}`;
// If req.body.filename contains '../', attacker can traverse directories
});Another manifestation occurs with Feathersjs services that store configuration or data files. If a service accepts a path parameter that gets passed directly to fs operations, an attacker could exploit path traversal to read sensitive files like /etc/passwd or application configuration files.
Feathersjs applications using NeDB or similar file-based databases are particularly vulnerable if the database path is configurable. An attacker might manipulate the path to point to a symbolic link that resolves to a critical system file, causing the application to read or overwrite it.
Feathersjs-Specific Detection
Detecting symlink attacks in Feathersjs requires examining both the codebase and runtime behavior. Start by auditing all file operations in your services, particularly those involving user input. Look for patterns like:
# Search for potentially vulnerable patterns
grep -r "fs\." services/ | grep -E "(path|join|resolve)"
grep -r "multer" services/ | grep -A5 "dest"
grep -r "config" services/ | grep -E "(path|file)"middleBrick's black-box scanning approach is particularly effective for detecting symlink vulnerabilities in Feathersjs applications. The scanner tests for path traversal by attempting to access files like /etc/passwd, ../../etc/passwd, and other sensitive paths. It also checks if the application properly handles symlinks in upload directories.
The middleBrick CLI can be used to scan your Feathersjs API endpoints:
npm install -g middlebrick
middlebrick scan https://yourapp.com/api/uploadFor OpenAPI spec analysis, middleBrick resolves $ref definitions and identifies endpoints that accept file paths or have file upload capabilities. It then correlates these findings with runtime tests to detect symlink vulnerabilities.
During scanning, middleBrick specifically tests for:
- Path traversal in file upload endpoints
- Symbolic link resolution in configurable paths
- Access to sensitive files through API endpoints
- Improper handling of
..sequences in paths - Race conditions between symlink creation and file access
The scanner provides severity ratings and specific remediation guidance tailored to Feathersjs applications, including code examples for fixing identified vulnerabilities.
Feathersjs-Specific Remediation
Remediating symlink attacks in Feathersjs requires a multi-layered approach. The most effective strategy combines input validation, safe path handling, and proper file system permissions.
For file uploads, use the multer middleware with strict configuration and validate filenames:
const multer = require('multer');
const path = require('path');
const crypto = require('crypto');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, '/safe-uploads/');
},
filename: (req, file, cb) => {
// Generate safe filename instead of using user input
cb(null, crypto.randomBytes(16).toString('hex') + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
limits: { fileSize: 1000000 }, // 1MB limit
fileFilter: (req, file, cb) => {
const allowedTypes = /jpeg|jpg|png|gif/;
const mimetype = allowedTypes.test(file.mimetype);
const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
if (mimetype && extname) {
return cb(null, true);
}
cb('Error: File upload only supports the following filetypes - ' + allowedTypes);
}
});For services that handle file paths, implement strict validation using the path module's normalization and comparison:
const validateFilePath = (userPath, allowedBaseDir) => {
const resolvedPath = path.resolve(allowedBaseDir, userPath);
const relativePath = path.relative(allowedBaseDir, resolvedPath);
// Check for path traversal
if (relativePath.startsWith('..') || relativePath.includes(' ')) {
throw new Error('Invalid file path');
}
// Check if the path is a symbolic link
const stats = fs.lstatSync(resolvedPath);
if (stats.isSymbolicLink()) {
throw new Error('Symbolic links are not allowed');
}
return resolvedPath;
};
// Usage in a Feathersjs service
app.get('/files/:filename', async (req, res) => {
try {
const safePath = validateFilePath(req.params.filename, '/safe-files/');
const fileContent = fs.readFileSync(safePath, 'utf8');
res.send(fileContent);
} catch (error) {
res.status(400).send({ error: 'Invalid file request' });
}
});For database file access, use absolute paths and validate against a whitelist of allowed directories:
const validateDatabasePath = (dbPath) => {
const allowedDirs = ['/var/lib/app-db/', '/opt/app-data/'];
const resolvedPath = path.resolve(dbPath);
// Ensure path is within allowed directories
const isAllowed = allowedDirs.some(dir => resolvedPath.startsWith(dir));
if (!isAllowed) {
throw new Error('Database path not allowed');
}
return resolvedPath;
};
// In your Feathersjs service
const dbService = new NeDB({
filename: validateDatabasePath(config.dbPath)
});Implement runtime protection by setting restrictive file permissions and using chroot-like isolation for upload directories. Consider using Docker containers or similar isolation mechanisms to limit the impact of any successful symlink attack.
Frequently Asked Questions
How does middleBrick detect symlink attacks in Feathersjs applications?
.. sequences in paths, resolves symbolic links safely, and prevents access to files outside designated directories. The scanner provides specific findings with severity ratings and Feathersjs-specific remediation guidance.Can symlink attacks in Feathersjs lead to remote code execution?
package.json or a configuration file, then modify it to execute malicious code when the application restarts.