# Path prefix check bypass

String-based private-path or deep-link prefix checks bypassed by symlinks, path aliases, or ../ traversal

_Area: Mobile app security. Seen in 4 disclosed reports; 3 confirmed bounties, median $500, range $250-$750; latest 2022-09-11. Updated 2026-10-23._

## How it works
A check decides whether a path is "private" or "allowed" by looking at the path string itself: does it contain `com.Slack`, does it start with `/data/data/`, does it begin with an allowed deep-link prefix. The assumption that breaks is that the string identifies the file. On Android the same file is reachable through many strings — symlinks, the `/data/user/0/` alias, `/proc/self/root`, and `../` traversal — so a path that fails the string test can still resolve to the protected target.

## Where it shows up
- Exported activities/services that accept a URI or file path and read or upload it.
- Checks using `contains`, `startsWith`, or a literal denylist of one path form.
- Deep-link handlers that validate scheme/host/prefix but never normalize the URI.
- Any WebView loaded from a deep-link-derived URL, especially with a JS bridge attached.

## How to review
Find every path/URI check on an exported component. The invariant: the check must run on the fully canonicalized, resolved path (symlinks followed, aliases collapsed, `..` removed) and compare against the canonical private directory — not a substring or one literal alias. For deep links, require normalization before prefix matching, and confirm the resulting URL cannot escape the allowed prefix. If the check operates on the raw input string, treat it as unsafe.

## Variants seen
- Symlink in attacker directory pointing into target sandbox bypasses a `contains('com.Slack')` check [E1](https://bugbountylibrary.com/r/h1%3A375083.md).
- Denylist of `/data/data/` misses the `/data/user/0/` alias to the same directory [E2](https://bugbountylibrary.com/r/h1%3A377107.md)[E3](https://bugbountylibrary.com/r/h1%3A1408692.md).
- Deep-link prefix check bypassed with `../` traversal, reaching a WebView with a JS bridge [E4](https://bugbountylibrary.com/r/h1%3A1087744.md).

## Why fixes fail
E3 is a regression of the same class: a prior fix added `startsWith("/data/data/")`, which the `/data/user/0/` alias defeats. Fixing one alias or one string form leaves the others open.

## Impact and severity
Reading app-private databases and prefs, account data theft, uploading private files to public shares, and arbitrary URL/JS execution via WebView bridge [E1](https://bugbountylibrary.com/r/h1%3A375083.md)[E2](https://bugbountylibrary.com/r/h1%3A377107.md)[E3](https://bugbountylibrary.com/r/h1%3A1408692.md)[E4](https://bugbountylibrary.com/r/h1%3A1087744.md). Severity is high where the component is exported and the target holds credentials or session data; worse when a JS bridge or upload sink turns file read into exfiltration.

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A375083.md
- E2: https://bugbountylibrary.com/r/h1%3A377107.md
- E3: https://bugbountylibrary.com/r/h1%3A1408692.md
- E4: https://bugbountylibrary.com/r/h1%3A1087744.md
