Skip to content

security: harden sanitize_path regex against #641 traversal class + regression tests#690

Open
wtfashwin wants to merge 1 commit into
ParisNeo:mainfrom
wtfashwin:security/issue-641-path-traversal-regex-hardening
Open

security: harden sanitize_path regex against #641 traversal class + regression tests#690
wtfashwin wants to merge 1 commit into
ParisNeo:mainfrom
wtfashwin:security/issue-641-path-traversal-regex-hardening

Conversation

@wtfashwin

Copy link
Copy Markdown

Summary

Fixes / addresses #641.

  • Replace the path-traversal regex shorthand \.\.+ with the explicit \.{2,} quantifier in both sanitize_path and sanitize_path_from_endpoint. Same matching behaviour, but the intent is unambiguous and trivially reviewable — exactly the form the issue reporter suggested.
  • Add tests/unitary_tests/test_security_sanitize_path.py, an 80-case regression suite that imports the real helpers and locks in the correct behaviour.

Why this change matters

The originally-reported regex (\.\.\.+, three-dot minimum) let canonical ../ through. The current pattern (\.\.+, two-dot minimum) is correct in behaviour, but uses the same compact shorthand whose readability ambiguity is what caused the original mistake in the first place. Switching to \.{2,} makes the lower bound visible at a glance and makes any future regression caught at code-review time, not after disclosure.

The test suite then pins the behaviour so the same class of bug cannot silently come back: if anyone ever changes the quantifier to require 3+ dots, the parametrised test_dot_run_of_any_length_ge_two_is_blocked[2] case fails and CI blocks the merge.

What the test suite covers

  • Every payload from the Bug: Path traversal regex pattern may not catch standard "../" sequences #641 PoC: ../etc/passwd, ../../etc/passwd, ..../etc/passwd, ...../etc/passwd, ..\\etc\\passwd — all rejected with HTTP 400.
  • Dot runs of length 2, 3, 4, 5, 8, 16 — all rejected.
  • Mid-path traversal (foo/../bar, foo/./../../bar) and Windows-style separators.
  • Shell command-substitution payloads ($(whoami), logs/$(id)/out.txt).
  • Collapsed-separator tricks (foo//bar, foo///bar).
  • Safe relative paths round-trip unchanged.
  • Opt-in flags (allow_absolute_path=True, allow_current_folder=True) still work, and traversal is still blocked even when absolute paths are explicitly allowed.
  • Every character in the unauthorised-punctuation set is rejected.

Test plan

  • python3 -m pytest tests/unitary_tests/test_security_sanitize_path.py -v — 80 passed, 0 failed, runs in <0.5s locally.
  • Confirmed the PoC bypasses from Bug: Path traversal regex pattern may not catch standard "../" sequences #641 (../etc/passwd, ../../etc/passwd, ..\\etc\\passwd, bare ..) all now raise HTTPException(400) through the real sanitize_path and sanitize_path_from_endpoint entry points.
  • No public API change, no behavioural change for any payload that is already correctly classified — purely a readability + regression-protection improvement.

Closes #641.

…Neo#641)

The path-sanitisation regex used the shorthand \.\.+ which expands to
"a dot followed by one or more dots", i.e. two or more consecutive dots.
That is semantically correct, but the shorthand is the same trap that
produced the original \.\.\.+ bug reported in ParisNeo#641 (three-dot minimum
allowing the canonical ../ traversal sequence through).

Replace it with the explicit \.{2,} quantifier in both sanitize_path
and sanitize_path_from_endpoint. Same matching behaviour, but the
intent is unambiguous and trivially reviewable.

Add tests/unitary_tests/test_security_sanitize_path.py — an 80-case
regression suite that imports the real helpers and pins:

  - every traversal payload from the ParisNeo#641 PoC (../, ../../, ..\\, dot
    runs of length 2..16) is rejected with HTTP 400
  - shell command substitution and collapsed-separator tricks are
    rejected
  - safe relative paths, opt-in absolute paths, and ./ when explicitly
    allowed continue to round-trip unchanged
  - every character in the unauthorised-punctuation set is rejected

If anyone ever "simplifies" the quantifier back to a 3+-dot form, the
parametrised dot-run test fails at length 2 and CI blocks the merge.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Path traversal regex pattern may not catch standard "../" sequences

1 participant