Path traversal lets a user reach files and directories outside the location an application meant to expose, because the application builds a file path from input it did not constrain. The result ranges from reading configuration files and secrets to overwriting code and gaining execution. In May 2024 CISA and the FBI published a Secure by Design alert on the class, noting 55 directory traversal vulnerabilities then listed in the Known Exploited Vulnerabilities catalog and impacts on hospital and school operations. This guide covers how traversal works, where it appears (web downloads, archive extraction, build systems, AI tooling), how to detect it and how to design it out. It is for developers, AppSec engineers and detection teams, and contains no payloads. For the wider family of web attacks, see the Web Application Attacks Guide.
Key takeaways
- Do not let users name files. Generate random identifiers server-side and store the original name as metadata. This removes the class rather than filtering it.
- If a path must come from input, resolve then check. Decode once, canonicalise to an absolute real path (resolving
..and symbolic links) and confirm it sits inside the permitted base directory. - Archives are a traversal vector. Entry names inside zip and tar files are untrusted paths; use extraction APIs with safety filters and reject entries that resolve outside the target.
- The real prize is usually a credential. Traversal reads configuration files, private keys and tokens, so what sits on disk next to the application decides the blast radius.
- Filesystem confinement limits damage. Run services with a dedicated identity, read-only mounts and confinement profiles so a traversal flaw cannot reach anything worth having.
How the attack works
MITRE classifies the weakness as CWE-22, Improper Limitation of a Pathname to a Restricted Directory, a Base weakness with two main children: CWE-23 Relative Path Traversal (dot-dot sequences) and CWE-36 Absolute Path Traversal (an absolute path supplied where a relative name was expected). It is closely related to CWE-73 External Control of File Name or Path. CWE-22 has appeared in every CWE Top 25 list from 2019 to 2025. See the CWE Top 25 Guide.
The mechanics are simple: the application joins a base directory with a user-influenced value and opens the result. If the value can contain parent-directory references, separators or an absolute path, the final location escapes the base. Variants exist because validation and use often see different representations of the same string:
- Encoding mismatches: the check runs before URL decoding, or input is decoded twice. CAPEC lists CAPEC-64, combining slashes and URL encoding to bypass validation logic.
- Platform differences: Windows accepts both separators, drive letters, UNC paths, alternate data streams (a colon in the name) and 8.3 short names; Unix does not. A check written for one platform fails on the other.
- Symbolic links: a path that looks local lexically may point elsewhere once links resolve, and a check-then-open sequence leaves a time-of-check to time-of-use (TOCTOU) window.
- Prefix confusion: a string prefix check treats
/srv/app-data-oldas inside/srv/app-data. Compare path components, not strings.
CAPEC records the pattern as CAPEC-126 Path Traversal, with CAPEC-139 Relative Path Traversal and CAPEC-76 Manipulating Web Input to File System Calls. Local and remote file inclusion are close relatives in which the traversed file is executed or interpreted rather than returned.
Where it shows up
| Location | Typical input | Typical consequence |
|---|---|---|
| File download, export and preview endpoints | Filename or path parameter, cookie, header | Arbitrary file read (CWE-23 or CWE-36) |
| File upload handlers | Client-supplied filename | Arbitrary file write, web shell in web root. See the File Upload Security Guide |
| Archive extraction (zip, tar, cab, jar) | Entry names and link targets inside the archive | Files written outside the extraction directory, often called zip slip |
| Templates, themes, plugins, language packs | Name of a file to include or load | File inclusion, code execution |
| Build and deployment systems | Build paths, context directories, artefact paths in config files | Exposure of build host secrets |
| AI tooling and MCP servers | File paths chosen by a model, prompt or resource names | Agent reads or writes outside its workspace |
| Edge appliances and file transfer products | Management API paths | Unauthenticated file read, configuration and credential theft |
In the local CISA KEV snapshot used for this guide (catalog 2026.10.21), 82 entries are tagged CWE-22 and 10 CWE-23. Examples include CVE-2021-41773 in Apache HTTP Server and CVE-2024-1708 in ConnectWise ScreenConnect, one of the two CVEs that prompted the CISA alert.
Client-side path traversal is a newer variant: browser code builds an API path from a URL parameter, so the request goes to an unintended endpoint with the user's session. The fix is the same principle applied on the client: encode path segments and never concatenate raw input into URLs. OWASP ASVS 5.0 V1.2.2 requires untrusted data in dynamically built URLs to be encoded for its context.
Impact
- Credential and secret exposure: environment files, application configuration, private keys, cloud credential files and container registry configs are plain files (ATT&CK T1552.001 Credentials In Files, T1005 Data from Local System).
- Discovery: reading system files reveals users, software versions and paths for the next step (T1083 File and Directory Discovery).
- Code execution: write-capable traversal can drop a web shell (T1505.003), overwrite scripts or configuration, or plant files a scheduled job later runs.
- Initial access: on internet-facing products the flaw is exploited as T1190 Exploit Public-Facing Application, often unauthenticated.
Where identity fits: the most damaging traversal reads are of non-human identity credentials, such as deployment tokens, service account keys and API keys stored beside the code. Keep long-lived secrets off disk, prefer short-lived workload identity and scope every token to one capability. See the Secrets Management Guide.
Detection
Before release
- Static analysis: trace taint from request parameters, headers, uploaded filenames and archive entries into file APIs (open, read, write, include, send-file and static-file helpers). CWE rates automated static analysis, manual review and dynamic scanning as high effectiveness for this weakness.
- Dynamic testing: fuzz every parameter that names a resource, with encoding and platform variants, and test archive handling with crafted entries in a lab. CISA asks manufacturers to perform formal directory traversal testing using OWASP guidance. See the Web Application Security Testing Guide.
- Unit tests at the helper: one shared safe-path function with tests for parent references, absolute paths, both separators, encoded forms, symbolic links and prefix confusion.
In production
| Signal | Source | Notes |
|---|---|---|
| Requests with encoded or raw parent-directory sequences, absolute paths or null bytes in parameters | Web server, reverse proxy, WAF logs | High volume of scanning noise; alert on 200 responses, not attempts |
| Application process reading files outside its normal set (system files, other apps' config, key files) | EDR file events, auditd watches, file access telemetry | D3FEND D3-FAPA File Access Pattern Analysis |
| New or modified files in web roots or code directories | File integrity monitoring | Write traversal or web shell |
| Use of credentials read from disk from a new source address | Cloud audit logs, identity provider logs | Often the first visible sign of a successful read |
A WAF rule for traversal sequences is a useful stopgap, and CWE lists it as one, but encoding tricks defeat signature matching and it does nothing for archive extraction or internal paths. See the Web Application Firewall Guide.
Prevention and hardening
Choosing a design
| Approach | When to use it | Trade-offs |
|---|---|---|
| Indirect reference: random ID mapped to a stored path | Uploads, downloads, user documents; the default | Needs a metadata store; removes the class |
| Fixed allowlist of names (ID to filename map) | Small known set: templates, reports, language packs | Simple and strong; does not scale to user content |
| Constrained name plus canonical containment check | When users must pick names in a directory | Must handle decoding, symbolic links and platform rules correctly |
| Object storage keys instead of filesystem paths | Cloud-native applications | Moves the problem to key prefixes and bucket policy; still validate prefixes |
OS-enforced root (Go os.Root, openat style APIs) | Libraries and services handling many untrusted paths | Strongest in-process control; platform caveats apply |
OWASP ASVS 5.0 V5.3.2 requires file paths to use internally generated or trusted data, or strict validation and sanitisation where user filenames must be used, to protect against path traversal, file inclusion and SSRF. V5.3.3 requires server-side decompression to ignore user-provided path information to prevent zip slip.
Implementation rules
- Generate names: the CISA alert recommends a random identifier per file with metadata stored separately, or failing that a tightly limited character set such as letters and numbers. The OWASP File Upload Cheat Sheet adds rejecting leading periods, sequential periods, leading hyphens and colons.
- Decode once, then canonicalise: the OWASP Input Validation Cheat Sheet warns against decoding the same input again downstream. CWE recommends resolving with functions such as
realpath()before checking. - Check containment by components: after resolving, confirm the result is the base directory or a descendant of it, comparing path components rather than raw string prefixes.
- Use the platform's safe APIs: Go 1.24 added
os.Root, which rejects operations escaping a directory, including through symbolic links, andfilepath.IsLocal(Go 1.20) reports whether a path stays local. Python'starfilehas extraction filters since 3.12, and the'data'filter is the default from 3.14; setfilter='data'explicitly on older versions. The Python documentation still warns: "Never extract archives from untrusted sources without prior inspection." - Serve through a handler: store uploads outside the web root, serve them by ID, disable per-directory configuration overrides in upload directories and never give uploaded files execute permission.
- Confine the process: dedicated service account, read-only file system where possible, chroot, AppArmor or SELinux profiles (CWE rates these as limited effectiveness on their own) and D3FEND D3-LFAM Local File Access Mediation.
Rollout plan
- Find the sinks: search all repositories for file open, include, send-file and archive extraction calls, and list which take any external input, including config files from users (build manifests) and model output.
- Build one safe-path helper per language, using the platform's rooted APIs where available, with the unit tests described above.
- Migrate high-exposure endpoints first: unauthenticated downloads and archive handling, then authenticated features, then internal tools.
- Remove secrets from reachable disk: move tokens and keys to a secrets manager or workload identity so a residual flaw finds nothing useful.
- Enable confinement in audit mode (AppArmor complain mode, SELinux permissive for the domain) for two to four weeks, review denials, then enforce. Rollback is a profile switch.
- Gate new code: add a SAST rule that blocks direct file API use with request data outside the helper, and include traversal in every penetration test scope.
Decision guidance
- Small teams: use object storage with generated keys and your framework's safe static-file serving; avoid writing your own path logic at all.
- Large or product organisations: treat CWE-22 as a class to eliminate, as CISA recommends: shared helpers, lint rules, formal traversal testing, and accurate CWE identifiers in your own CVE records.
- Customers of software: CISA suggests asking manufacturers whether they have conducted formal directory traversal testing; prioritise KEV-listed traversal flaws on internet-facing products.
Measuring progress
- File API calls taking external input that bypass the safe-path helper, trending to zero.
- Percentage of archive extraction code using safety filters or rooted APIs.
- Long-lived secrets found on application hosts and build machines.
- Mean time to patch KEV-listed CWE-22 flaws on internet-facing systems.
- Percentage of services running with enforced filesystem confinement.
Framework mapping
| Framework | Reference | Relevance |
|---|---|---|
| NIST SP 800-53 Rev. 5 | SI-10 Information Input Validation; SA-11 Developer Testing and Evaluation; AC-6 Least Privilege; SI-4 System Monitoring | Validation, testing, confinement, monitoring |
| NIST CSF 2.0 | PR.PS-06; DE.CM-09; ID.RA-01 | Secure development, monitoring, vulnerability identification |
| OWASP ASVS 5.0 | V5.3.2, V5.3.3, V1.2.2 | Verification requirements |
| ISO/IEC 27001:2022 | Annex A 8.28 Secure coding | Policy anchor |
| MITRE ATT&CK | T1190, T1083, T1005, T1552.001, T1505.003 | Detection engineering |
| MITRE D3FEND | D3-LFAM, D3-FAPA | Countermeasures |
Lessons from incidents
- Config files are input. In the Smithery.ai MCP hosting breach of 2025, the build process did not validate the
dockerBuildPathsetting in a user'ssmithery.yaml. A parent-directory value made the builder's home directory the build context, exposing a Docker config file holding a fly.io token that controlled the organisation's 3,243 apps, mostly hosted MCP servers. GitGuardian researchers reported it under responsible disclosure and Smithery rotated the token and fixed the flaw within two days. - Secrets on the build host turn a file read into full control. The same case shows why deployment tokens should be scoped to one capability and kept off machines that process user-supplied builds.
- Edge products repeat the pattern. The CISA alert was prompted by campaigns exploiting traversal in widely used products, including CVE-2024-1708 in ConnectWise ScreenConnect, which affected critical infrastructure.
Practitioner checklist
- Replace user-supplied filenames with server-generated identifiers and store original names as metadata.
- Route all file access from external input through one tested safe-path helper per language.
- Decode once, canonicalise with symbolic links resolved and check containment by path components.
- Use rooted or filtered APIs for archive extraction and reject entries or links that escape the target.
- Store uploads outside the web root, serve them by ID and never give them execute permission.
- Remove long-lived secrets from application hosts and build machines; prefer workload identity.
- Run services under dedicated identities with read-only mounts and enforced confinement profiles.
- Alert on successful traversal-pattern requests and on application processes reading unusual files.
- Include traversal, archive and client-side path cases in SAST rules and penetration test scope.
Standards and references
- MITRE CWE: CWE-22 Improper Limitation of a Pathname to a Restricted Directory
- CISA and FBI: Secure by Design Alert, Eliminating Directory Traversal Vulnerabilities in Software
- OWASP: Application Security Verification Standard 5.0
- OWASP: File Upload Cheat Sheet
- OWASP: Input Validation Cheat Sheet
- The Go Blog: Traversal-resistant file APIs
- Python Software Foundation: tarfile, Extraction filters
- MITRE CAPEC: Path Traversal (CAPEC-126)
Related NHI Mgmt Group resources: Command Injection Guide · Server-Side Template Injection (SSTI) Guide · File Upload Security Guide · MCP Security Guide