Path Traversal Explained

Share

TL;DR

Path traversal (or directory traversal) happens when user input is used to construct file paths without proper validation. Attackers use ../ sequences to escape the intended directory and read sensitive files like /etc/passwd or your .env file. Always resolve paths and verify they stay within the allowed directory.

How Path Traversal Works

Vulnerable file serving
// User requests: /api/files?name=../../../etc/passwd

app.get('/api/files', (req, res) => {
  const filename = req.query.name;
  const filepath = path.join('/uploads', filename);  // VULNERABLE!

  // This reads /etc/passwd, not a file in /uploads
  res.sendFile(filepath);
});

Common targets: /etc/passwd, .env, config files, source code, private keys. On Windows: C:\Windows\System32\config\SAM, web.config

Bypass Attempts

Simple blacklisting of "../" is not enough. Attackers use encodings:

  • ..%2f (URL encoded)
  • ..%252f (double encoded)
  • ....// (after stripping ../)
  • ..\ (Windows paths)

How to Prevent Path Traversal

Safe file path handling
import path from 'path';

const UPLOAD_DIR = '/var/app/uploads';

app.get('/api/files', (req, res) => {
  const filename = req.query.name;

  // Resolve to absolute path
  const requestedPath = path.resolve(UPLOAD_DIR, filename);

  // Verify it's still within the allowed directory
  if (!requestedPath.startsWith(UPLOAD_DIR + path.sep)) {
    return res.status(403).json({ error: 'Access denied' });
  }

  // Now safe to use
  res.sendFile(requestedPath);
});

Is path.join() safe?

No. path.join() just combines paths, it doesn't prevent traversal. You must use path.resolve() and then verify the result is within your allowed directory.

What about symbolic links?

Symlinks can also be used for traversal. Use fs.realpath() to resolve symlinks before checking the path, or disable symlinks in your upload directory.

Scan for Path Traversal

Our scanner tests file endpoints for path traversal vulnerabilities.

Start Free Scan
Vulnerability Guides

Path Traversal Explained