Vulnerability library  /  Path traversal

Path traversal

Path traversal

Path traversal lets untrusted input escape an intended directory and access other files or locations. It can expose secrets, overwrite application data, or turn file-handling features into server compromise.

Also known as
Directory traversal · Dot-dot-slash attack · File path traversal
Typical severity · Medium to Critical
Last updated
On this page: What it is
  1. 1 · What it is
  2. 2 · Why it matters
  3. 3 · Examples
  4. 4 · How to fix it
  5. 5 · How to test for it
  6. References
  7. Related

What it is#

Path traversal occurs when an application uses untrusted input as part of a filesystem path without reliably confining the result to an approved directory. Dot segments, absolute paths, encoded separators, symbolic links, archive entries, or platform-specific path rules can escape the intended location.

The flaw is not limited to downloads. It can affect uploads, log viewers, template selection, archive extraction, backup restoration, file deletion, static-file handlers, and any feature that reads or writes a path.

Normalization matters. Filtering the literal text ../ is not sufficient because decoding, Unicode handling, Windows separators, nested encodings, and filesystem links can change the path after a check.

Why it matters#

  • Read source code, configuration, credentials, keys, logs, or other users' files.
  • Overwrite application files, startup configuration, scheduled jobs, or authorized-key material.
  • Delete files outside the intended workspace.
  • Extract malicious archive entries outside the destination directory, often called Zip Slip.
  • Cross tenant boundaries when customer-controlled directories share a filesystem.
  • Escalate to code execution when a writable path is later loaded or executed.
Typical severity

Medium for limited disclosure of low-sensitivity files. High to critical when secrets can be read or executable, configuration, or authentication-related files can be written. Actual severity depends on context: who is affected, what data or actions are reachable, and existing controls.

Examples#

✕ Vulnerablejavascript
// Vulnerable: the filename can leave the reports directory.
import path from 'node:path';

app.get('/reports/download', requireLogin, (req, res) => {
  const filename = String(req.query.file);
  res.sendFile(path.join('/srv/reports', filename));
});
✓ Fixedjavascript
// Fixed: expose an identifier, then look up a server-owned storage name.
app.get('/reports/:id/download', requireLogin, async (req, res) => {
  const report = await db.report.findFirst({
    where: { id: req.params.id, accountId: req.user.accountId },
    select: { storageKey: true, downloadName: true },
  });
  if (!report) return res.sendStatus(404);

  // storageKey was generated by the server, not supplied as a path by the user.
  res.download(`/srv/reports/${report.storageKey}`, report.downloadName);
});

If a path must be accepted, resolve it against a fixed root and verify the final canonical path remains beneath that root. That check must also account for symbolic links and race conditions.

How to fix it#

1. Do not expose filesystem names. Use an opaque record ID and map it to a server-generated storage key after checking ownership and authorization.

2. Generate destination names. For uploads, create random server-side names and store the original display name only as metadata.

3. Canonicalize once, then enforce containment. Decode at a defined boundary, resolve the complete path, and verify it is inside the expected root using path-aware functions. Include a trailing path separator in prefix comparisons.

4. Reject absolute and ambiguous paths. Disallow dot segments, alternate separators, drive letters, UNC paths, null bytes, device names, and unexpected Unicode forms according to the target platform.

5. Defend against symbolic links. Open files using platform controls that avoid following links where available, verify file descriptors rather than only names, and keep attacker-writable directories separate from trusted data.

6. Extract archives safely. Inspect every entry after normalization, reject absolute paths and links, enforce a single extraction root, and limit expanded size, file count, and nesting.

7. Use least filesystem privilege. The application should not be able to read unrelated secrets or write executable and configuration directories.

8. Apply access control independently. A safe path does not prove the caller may access the file. Check tenant, owner, role, and purpose before opening it.

How to test for it#

  • Inventory all file reads, writes, deletes, downloads, uploads, archive operations, template selection, and log-viewing features.
  • Use a dedicated harmless canary file immediately outside a test directory and confirm it cannot be reached.
  • Test dot segments, absolute paths, mixed separators, repeated encoding, trailing dots or spaces, Unicode normalization, and Windows-specific forms where applicable.
  • Test symbolic links and archive entries in an isolated fixture directory; do not target operating-system or production files.
  • Verify that path checks occur after the application's final decoding and before the filesystem operation.
  • Confirm that valid files belonging to another test user or tenant remain inaccessible even when their identifiers are known.
  • Add unit tests for normalization and containment on every supported operating system, plus integration tests against the real storage backend.

References#

Permalinklibrary.infinity8labs.com/path-traversal/JSON
Found this in Breachvane? Your finding links here for background. Evidence, affected assets and retest status are in your Breachvane ↗ (opens in a new tab) workspace. Need help fixing it? Talk to us.