cybersecurity · intermediate · ~20 min

Detect path-traversal patterns in a string

Defensive string scanning for a well-defined set of malicious sub-patterns.

Challenge

Reject an untrusted path that tries to climb out of its directory (../../../etc/passwd) before any file is opened.

Task

Implement int has_path_traversal(const char *path) that returns 1 if path contains an obvious traversal pattern, else 0.

Treat these as traversal:

  • A .. segment delimited by /, \, or a string boundary (e.g. .., a/.., ../b, a/../b, a\..\b).
  • The URL-encoded form %2e%2e in any letter-case combination (%2E%2E, %2e%2E, ...).

A plain .. inside a name (foo..bar) is NOT traversal, and a leading / by itself (/etc/passwd) is NOT traversal — only .. segments count.

Input

  • path: a NUL-terminated path candidate the grader passes.

Output

Returns int: 1 if any traversal pattern matches, else 0.

Example

has_path_traversal("foo/bar")        ->   0
has_path_traversal("..")             ->   1
has_path_traversal("foo/../bar")     ->   1
has_path_traversal("foo..bar")       ->   0   (".." inside a name)
has_path_traversal("..\Windows")    ->   1
has_path_traversal("%2e%2e/foo")     ->   1
has_path_traversal("/etc/passwd")    ->   0
has_path_traversal("")               ->   0

Edge cases

  • Empty input returns 0.
  • A single dot segment (a/./b) is not traversal.
  • .. must form a complete segment — a lone strstr for ".." wrongly flags foo..bar.

Rules

  • Defensive check only — it does not open or touch any file. Production code should additionally canonicalise with realpath and confirm the result stays under an allowed root.

Why this matters

Web servers and file-API gateways must reject paths like ../../../etc/passwd before opening anything. The check looks simple but has subtle traps — URL-encoded %2e%2e, mid-string .., and Windows ..\ are all real-world bypasses.

Input format

A NUL-terminated path candidate path.

Output format

An int: 1 if any traversal pattern matches, else 0.

Constraints

O(strlen(path)); no allocations; string check only (does not open files).

Starter code

int has_path_traversal(const char *path) { /* TODO */ return 0; }

Common mistakes

Using a single strstr for ".." — that catches "foo..bar" too. The dots must form a complete segment.

Edge cases to handle

Empty input; literal ".." alone; double-dot inside a word ('foo..bar'); URL-encoded form.

Complexity

O(n).

Background lessons

Up next

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.