Documentation

Filesystem Security Checks

Filesystem security checks identify vulnerabilities that could allow attackers to access files outside intended directories or read sensitive system files.

fs-sensitive-path

Severity: High

What It Detects

Access to sensitive file paths:

  • SSH configuration (~/.ssh/)
  • AWS credentials (~/.aws/)
  • GPG keys (~/.gnupg/)
  • Kubernetes configs (~/.kube/)
  • Environment files (.env)
  • System credential files

Why It's Dangerous

Accessing sensitive paths can expose:

  • Private SSH keys (server access)
  • Cloud credentials (AWS, GCP, Azure)
  • Database passwords
  • API keys and tokens
  • Application secrets

Example Vulnerable Code

// Reading SSH keys
const sshKey = fs.readFileSync(`${homeDir}/.ssh/id_rsa`);  // DANGEROUS!
 
// Reading AWS credentials
const awsCreds = fs.readFileSync(`${homeDir}/.aws/credentials`);  // DANGEROUS!
 
// Reading environment files
const envContent = fs.readFileSync('.env');  // DANGEROUS if exposed!

Safe Alternative

// Don't read credential files directly
// Instead, use environment variables or SDKs
 
// For AWS - use SDK's built-in credential chain
import { fromEnv, fromIni } from '@aws-sdk/credential-providers';
const client = new S3Client({
  credentials: fromEnv(), // Reads from environment
});
 
// For SSH - use ssh-agent or credential helpers
import { createAgent } from 'ssh-agent';
const agent = await createAgent();
 
// For configuration - use environment variables
const dbPassword = process.env.DB_PASSWORD;

fs-path-traversal

Severity: High

What It Detects

Path traversal patterns:

  • ../ sequences that could escape directories
  • Unsanitized path concatenation
  • User input in file paths

Why It's Dangerous

Path traversal allows attackers to:

  • Read files outside the intended directory
  • Access system files (/etc/passwd)
  • Read application secrets
  • Potentially write to arbitrary locations

Example Vulnerable Code

// User-controlled file path
const fileName = req.query.file;
const content = fs.readFileSync(`./uploads/${fileName}`);  // DANGEROUS!
// Attacker input: "../../../etc/passwd"
 
// Path concatenation without validation
const filePath = userDir + '/' + userFile;
const data = fs.readFileSync(filePath);  // DANGEROUS!
 
// Template with user input
const templatePath = `./templates/${userTemplate}.html`;

Safe Alternative

import path from 'path';
 
// Resolve and validate the path
const baseDir = path.resolve('./uploads');
const requestedPath = path.resolve(baseDir, fileName);
 
// Ensure path is within allowed directory
if (!requestedPath.startsWith(baseDir)) {
  throw new Error('Invalid file path');
}
 
const content = fs.readFileSync(requestedPath);

More robust solution:

import path from 'path';
 
function getSafePath(baseDir, userPath) {
  // Resolve both paths to absolute
  const base = path.resolve(baseDir);
  const full = path.resolve(base, userPath);
 
  // Check that resolved path starts with base
  if (!full.startsWith(base + path.sep) && full !== base) {
    throw new Error('Path traversal attempt detected');
  }
 
  // Additional check: no .. in the resolved path
  const relative = path.relative(base, full);
  if (relative.startsWith('..')) {
    throw new Error('Invalid path');
  }
 
  return full;
}
 
// Usage
const safePath = getSafePath('./uploads', userInput);
const content = fs.readFileSync(safePath);

Summary

| Check | Severity | Key Fix | |-------|----------|---------| | fs-sensitive-path | High | Don't read credential files; use env vars | | fs-path-traversal | High | Validate paths are within allowed directories |

Best Practices

1. Use Absolute Path Resolution

Always resolve paths to absolute before comparison:

const resolved = path.resolve(baseDir, userInput);

2. Implement Path Allowlists

const allowedDirs = [
  path.resolve('./public'),
  path.resolve('./uploads'),
];
 
function isPathAllowed(filePath) {
  const resolved = path.resolve(filePath);
  return allowedDirs.some(dir =>
    resolved.startsWith(dir + path.sep) || resolved === dir
  );
}

3. Sanitize User Input

// Remove path separators and traversal
const sanitize = (input) => {
  return path.basename(input); // Only filename, no directory
};
 
const safeFile = sanitize(userInput);
const filePath = path.join('./uploads', safeFile);

4. Use chroot or Containers

For high-security scenarios:

  • Run file operations in a chroot jail
  • Use containerization to limit filesystem access
  • Mount only necessary directories

Next Steps