CWE-22HighMITRE entry

Path Traversal

Improper Limitation of a Pathname to a Restricted Directory (Path Traversal)

What it is

CWE-22 occurs when an application accepts user input as a file path and resolves it without restricting access to an intended directory. Attackers use sequences like ../ or absolute paths to escape the intended directory and read or write arbitrary files (typically /etc/passwd, application source code, or AWS credentials).

Why it matters

Path traversal exposes anything the application's service account can read: configuration files with secrets, SSH keys, AWS credentials, source code, customer data files. In write contexts, it allows attackers to overwrite application code or system binaries. The pattern recurs in image servers, document viewers, backup utilities, and file-upload-then-download flows.

Common patterns

  • Concatenating user input into a path: fs.readFile('/uploads/' + req.params.filename).
  • Using req.params.path or req.query.file directly in os.path.join.
  • Static file servers with insufficient root restriction.
  • Archive extraction that does not validate entry paths (the 'Zip Slip' variant).
  • URL-based file routing in image proxies and document viewers.

Languages affected

PythonJavaScriptTypeScriptRubyGoJavaPHP

What Deva detects

Deva tracks input from request handlers, message bodies, and archive entries to file-system operations (fs.readFile, fs.writeFile, fs.createReadStream, open, Path.read_text, FileInputStream, ServletContext.getResource). The scanner reports a finding when an input flows to a path operation without passing through a recognized canonicalization or allowlist check.

Example

Vulnerable

from flask import send_from_directory, request

@app.route('/download')
def download():
    filename = request.args.get('file')
    return send_from_directory('/var/uploads', filename)

Fixed

import os
from flask import send_from_directory, request, abort

UPLOAD_ROOT = '/var/uploads'

@app.route('/download')
def download():
    filename = request.args.get('file', '')
    # Normalize and confirm the resolved path stays within UPLOAD_ROOT
    resolved = os.path.realpath(os.path.join(UPLOAD_ROOT, filename))
    if not resolved.startswith(UPLOAD_ROOT + os.sep):
        abort(404)
    return send_from_directory(UPLOAD_ROOT, filename)

Explanation

send_from_directory has some protections but is bypassable with crafted paths (../, absolute paths, URL-encoded variants). The fix realpath()'s the candidate, then verifies the resolved path is still inside the upload root. This canonical-then-check pattern is the standard defense for path traversal across languages.

Where this fits in OWASP Top 10

Compliance framework mapping

FrameworkControls
OWASP Top 10 (2021)
A01:2021 Broken Access Control
NIST 800-53 Rev 5
AC-3 Access EnforcementSI-10 Information Input Validation
PCI-DSS v4.0
6.2.4 Software engineering techniques
CMMC 2.0 L2
AC.L2-3.1.3 CUI flow control

Related CWEs

Deva detects CWE-22 alongside 970+ other CWE patterns at write time, with AI-assisted fix generation that maintains compliance.