Script Valley
Web Security Fundamentals for Developers
Injection Attacks: SQL, Command, and LDAPLesson 2.4

Path traversal attacks: how attackers escape your intended directory

path traversal mechanics, ../ sequences, URL decoding bypass, path.resolve and path.join, realpath validation, allowlist of accessible paths

Path Traversal

Path traversal diagram

Path traversal lets attackers read files outside your intended directory by injecting ../ sequences into a filename parameter. A successful attack can expose /etc/passwd, source code, private keys, or environment files.

The Vulnerable Pattern

// VULNERABLE
const filePath = path.join(__dirname, 'uploads', req.query.file);
// req.query.file = '../../etc/passwd'
// Resolved: /app/uploads/../../etc/passwd → /etc/passwd
res.sendFile(filePath);

The Fix: Validate the Resolved Path

const path = require('path');
const fs = require('fs');

const BASE_DIR = path.resolve(__dirname, 'uploads');

app.get('/file', (req, res) => {
  const requested = path.resolve(BASE_DIR, req.query.file);

  // Ensure the resolved path is still inside BASE_DIR
  if (!requested.startsWith(BASE_DIR + path.sep)) {
    return res.status(403).json({ error: 'Access denied' });
  }

  if (!fs.existsSync(requested)) {
    return res.status(404).json({ error: 'File not found' });
  }

  res.sendFile(requested);
});

URL Encoding Bypass

Attackers also encode traversal sequences: %2e%2e%2f decodes to ../. Using path.resolve handles this automatically because Node's path module resolves the logical path before the startsWith check. Do not manually strip ../ from strings—it's easy to get wrong with double encoding like %252e%252e%252f.

Up next

Input validation vs output encoding: which to use when

Sign in to track progress