HIGH symlink attackfeathersjs

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/upload

For 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?
middleBrick uses black-box scanning to test for path traversal vulnerabilities by attempting to access sensitive files through API endpoints. It checks if the application properly handles .. 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?
Yes, symlink attacks can potentially lead to remote code execution if an attacker can manipulate symbolic links to point to critical system files or application configuration files. For example, if a Feathersjs application writes to a file path controlled by the attacker, they could create a symlink to package.json or a configuration file, then modify it to execute malicious code when the application restarts.