REFERENCE GUIDE

Path traversal and canonicalization boundaries

Traversal happens when an attacker-controlled path escapes an intended filesystem root.

Also known as: directory traversal · LFI

path-traversalweb

Mechanism

Traversal happens when an attacker-controlled path escapes an intended filesystem root. The vulnerable operation may be reading, writing, extracting an archive, or resolving a template. Percent decoding, separator conversion, dot-segment removal, and symlink resolution can occur in different layers. A string-prefix check is weaker than checking the final resolved path against the allowed directory boundary.

Practical method

Find the parameter that names a file and first request a known allowed file. Test dot segments and encoding separately while keeping the suffix constant. Establish whether the application appends an extension or prepends a directory. Use a harmless fixture outside the allowed root in a local lab to distinguish traversal from an ordinary missing-file response.

from pathlib import Path
root = Path("fixtures/public").resolve()
candidate = (root / user_path).resolve()
if not candidate.is_relative_to(root):
    raise ValueError("outside allowed root")

Interpreting evidence

Compare returned bytes with the expected fixture, not just the HTTP status. Error paths can expose server-side names without permitting reads. For write operations, verify the actual destination after all archive or filename transformations.

Pitfalls and limits

The resolved-path check can still race with symlink changes in writable directories. OS-specific separators, drive prefixes, and case rules matter. A normalizing proxy may remove a candidate before the backend sees it.

Selected licensed upstream examples

These equivalent-looking path fragments intentionally remain distinct: they test literal traversal, platform separator handling, one decoding pass, and two decoding passes. Apply them to a harmless fixture path and determine which layer normalizes each form. Overlong UTF-8 and historical null-byte variants from the broader collection are omitted because support is implementation-specific and often obsolete.

../
..\
%2e%2e%2f
%252e%252e%252f

Attribution: PayloadsAllTheThings; MIT. Selected lines, explanatory notes added. Pinned upstream file.

Sources & further reading

  1. Directory Traversal ↗payloads
  2. Pathlib path operations ↗python
  3. Selected PayloadsAllTheThings example ↗payloads · MIT · revision 3ac27901c711bdf3f5b65a7b1d1820a1f65bd09a

Content license: CC-BY-4.0; selected attributed excerpts MIT. Source-derived sections retain their cited licenses and redistribution notices. How this reference is compiled →