# Path traversal check bypass via encoding

Check runs on a different string than the file API opens: decode, normalize, or truncate after validation

_Area: Web injection and code execution. Seen in 14 disclosed reports; 5 confirmed bounties, median $1,500, range $480-$17,000; latest 2026-09-03. Updated 2026-10-23._

## How it works
A path is validated, then transformed before use, so the check and the file operation disagree about what the string means. The invariant that breaks: the exact string validated must be the exact string opened. Two root causes: (1) stage ordering — decode, normalize, fragment-strip, or truncation happens after the check; (2) token mismatch — the filter looks for `..` but the OS/API also treats `.+.`, double-encoded dots, or backslashes as traversal, or matches a substring instead of a suffix.

## Where it shows up
- A decode or `decodeURIComponent` runs after the browser/framework already normalized the URL [E3](https://bugbountylibrary.com/r/blog%3Ablog-trailofbits-com-2023-02-23-escaping-well-configured-vscode-extensions-for-profit.md).
- A patch decodes once, but a second decode pass still yields `..` [E5](https://bugbountylibrary.com/r/h1%3A1404731.md).
- Path is checked, then a fragment (`#`) or query is stripped before read [E6](https://bugbountylibrary.com/r/blog%3Aassetnote-io-resources-research-leveraging-an-order-of-operations-bug-to-achieve-rce-in-sitecore-8-x-10-x.md).
- Extension check uses substring match (`*.HL?` anywhere) instead of suffix [E4](https://bugbountylibrary.com/r/h1%3A458842.md).
- A sink appends a fixed extension, but lower-level APIs truncate at a null byte [E1](https://bugbountylibrary.com/r/blog%3Aaikido-dev-blog-meccha-chameleon-rce.md).
- Windows/ASP.NET APIs accepting `.+.` as a traversal segment [E2](https://bugbountylibrary.com/r/blog%3Asamcurry-net-reading-asp-secrets-for-17000.md).
- Sanitization runs on ciphertext, then the value is decrypted and used [E7](https://bugbountylibrary.com/r/blog%3Aassetnote-io-resources-research-exploiting-an-order-of-operations-bug-to-achieve-rce-in-oracle-opera.md).
- Containment check uses `strpos`/`startsWith` on a substring, not a resolved path [E8](https://bugbountylibrary.com/r/h1%3A1626210.md)[E3](https://bugbountylibrary.com/r/blog%3Ablog-trailofbits-com-2023-02-23-escaping-well-configured-vscode-extensions-for-profit.md).

## How to review
Trace the value from input to file open. Confirm the check runs on the final, fully decoded, fully normalized string, and that the same string is passed to the file API. Verify extension checks use suffix matching on the canonical path, not substring. For null-byte sinks, confirm the string handed to the OS API has no embedded null and that the appended extension survives truncation [E1](https://bugbountylibrary.com/r/blog%3Aaikido-dev-blog-meccha-chameleon-rce.md). For archives, confirm each entry resolves inside the target directory after cleaning. For containment checks, confirm `startsWith(rootPath + separator)` — a bare `startsWith(rootPath)` lets `/root-evil` pass [E3](https://bugbountylibrary.com/r/blog%3Ablog-trailofbits-com-2023-02-23-escaping-well-configured-vscode-extensions-for-profit.md). Prefer realpath/canonicalization over lexical clean when symlinks or alternate tokens are possible.

## Variants seen
- Double encoding surviving single-pass decode [E5](https://bugbountylibrary.com/r/h1%3A1404731.md)
- Decode-after-normalize reintroducing `../` [E3](https://bugbountylibrary.com/r/blog%3Ablog-trailofbits-com-2023-02-23-escaping-well-configured-vscode-extensions-for-profit.md)
- Validate-before-fragment-strip: `web.config#.js` passes the `.js` check, then `#` is stripped [E6](https://bugbountylibrary.com/r/blog%3Aassetnote-io-resources-research-leveraging-an-order-of-operations-bug-to-achieve-rce-in-sitecore-8-x-10-x.md)
- Substring extension match [E4](https://bugbountylibrary.com/r/h1%3A458842.md)
- Null-byte truncation stripping an appended extension [E1](https://bugbountylibrary.com/r/blog%3Aaikido-dev-blog-meccha-chameleon-rce.md)
- Alternate traversal token `.+` [E2](https://bugbountylibrary.com/r/blog%3Asamcurry-net-reading-asp-secrets-for-17000.md)
- Sanitize-before-decrypt on encrypted parameters [E7](https://bugbountylibrary.com/r/blog%3Aassetnote-io-resources-research-exploiting-an-order-of-operations-bug-to-achieve-rce-in-oracle-opera.md)
- Substring containment check (`strpos`) instead of resolved-path check [E8](https://bugbountylibrary.com/r/h1%3A1626210.md)

## Why fixes fail
Fixes fail when they patch one stage but not the invariant: the check still runs on a string that differs from the one opened. E5 decoded once but missed a second pass. E6 validated before the fragment strip. E3 compared prefixes without a separator. Each fix addressed a token or a stage, not the ordering guarantee.

## Impact and severity
Led to arbitrary file read of secrets (web.config, cloud credentials) [E2](https://bugbountylibrary.com/r/blog%3Asamcurry-net-reading-asp-secrets-for-17000.md)[E6](https://bugbountylibrary.com/r/blog%3Aassetnote-io-resources-research-leveraging-an-order-of-operations-bug-to-achieve-rce-in-sitecore-8-x-10-x.md), arbitrary file write and DLL/webshell loading [E4](https://bugbountylibrary.com/r/h1%3A458842.md)[E1](https://bugbountylibrary.com/r/blog%3Aaikido-dev-blog-meccha-chameleon-rce.md), and RCE via deserialization or CGI [E6](https://bugbountylibrary.com/r/blog%3Aassetnote-io-resources-research-leveraging-an-order-of-operations-bug-to-achieve-rce-in-sitecore-8-x-10-x.md)[E5](https://bugbountylibrary.com/r/h1%3A1404731.md)[E7](https://bugbountylibrary.com/r/blog%3Aassetnote-io-resources-research-exploiting-an-order-of-operations-bug-to-achieve-rce-in-oracle-opera.md). Severity rises when the read file holds credentials or when write reaches an executable path.

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Aaikido-dev-blog-meccha-chameleon-rce.md
- E2: https://bugbountylibrary.com/r/blog%3Asamcurry-net-reading-asp-secrets-for-17000.md
- E3: https://bugbountylibrary.com/r/blog%3Ablog-trailofbits-com-2023-02-23-escaping-well-configured-vscode-extensions-for-profit.md
- E4: https://bugbountylibrary.com/r/h1%3A458842.md
- E5: https://bugbountylibrary.com/r/h1%3A1404731.md
- E6: https://bugbountylibrary.com/r/blog%3Aassetnote-io-resources-research-leveraging-an-order-of-operations-bug-to-achieve-rce-in-sitecore-8-x-10-x.md
- E7: https://bugbountylibrary.com/r/blog%3Aassetnote-io-resources-research-exploiting-an-order-of-operations-bug-to-achieve-rce-in-oracle-opera.md
- E8: https://bugbountylibrary.com/r/h1%3A1626210.md
