Escaping the intended root
Path traversal occurs when untrusted path data makes a filesystem operation reach an object outside the intended directory or namespace. The input can use parent segments, absolute paths, alternate separators, encoded bytes, symbolic links, device names, archive entries, or platform-specific aliases.
The result can disclose secrets, overwrite configuration, place executable content, delete data, or read process and system files.
Use identifiers, not paths
Prefer a server-generated object identifier mapped to storage metadata. Do not let a caller supply a filesystem path. If the product needs a relative name, define its allowed segments, characters, length, extension, and semantics. Reject absolute names, empty or dot segments, reserved names, null bytes, and invalid encoding.
Resolve the candidate against a fixed root with the platform's path API. Verify that the canonical result remains inside the root. Open the object through a directory handle or platform mechanism that prevents escape when available. Do not validate one string and later open a separately reconstructed string.
Races, links, and archives
An attacker can change a symbolic link or mount between a path check and file use. Avoid a check-then-open sequence. Open relative to a trusted directory and request no-follow behavior where supported. Keep writable upload storage separate from executable, configuration, and application directories.
Archive extraction must validate every entry after decoding. Reject absolute paths, parent escape, links, devices, and excessive expansion. Create a fresh extraction root with narrow permissions and resource limits.
Failure and residual risk
Removing ../ once can be bypassed through encoding, alternate separators, repeated decoding, or nested patterns. A prefix string comparison can confuse /safe/root-two with /safe/root. Case and Unicode rules vary by filesystem. A valid path can still name another user's authorized file.
Pomerium boundary
Pomerium can decide whether a caller may reach a file-management route. It cannot determine which local file an upstream path resolves to or prevent a symbolic-link race. The application must map authorized object identifiers to safe storage operations and enforce object permission after resolution.
Evaluation checklist
- Can the interface use an opaque server-generated object identifier instead of a path?
- Is decoding and canonical resolution performed once before use?
- Does the final object stay below a fixed root under the platform's real path rules?
- Can a link, mount, archive entry, or concurrent change invalidate the check?
- Is writable content isolated from executable, configuration, and secret locations?
- Does object authorization apply to the resolved object, not only the requested string?
