feat(scan): --path-traversal mutator for OWASP A01 scope-escape (../etc/passwd, encoded, double-encoded, nested, null-byte, absolute)#30
Merged
Conversation
…d/nested/null-byte/absolute payloads against etc/passwd, proc/self/environ, win.ini for OWASP A01 path-traversal / LFI Adds the PathTraversal mutator (off by default behind --path-traversal). Disjoint from --forbidden-bypass (which reshapes the path to resolve back to the SAME handler, e.g. /admin/..;/admin) and from --swap-object / --enumerate (which stay inside the resource collection): path-traversal escapes OUT of the resource subtree the route prefix was supposed to confine the caller to, reaching OS-sensitive files or sibling-tenant directories. Six techniques × three targets = 18 deterministic variants per eligible endpoint, emitted in sorted-by-technique then sorted-by-target order: - dot-dot-slash: ../../../../../../etc/passwd - dot-dot-encoded: ..%2f..%2f...etc/passwd (RawPath survives) - dot-dot-double-encoded: ..%252f..%252f...etc/passwd - nested-dot-dot: ....//....//...etc/passwd - null-byte-suffix: ../../...etc/passwd%00 - absolute-path: /etc/passwd (no `..` at all) Targets: etc/passwd, proc/self/environ, windows/win.ini. Every variant keeps the caller's own credentials (Identity == nil) — the bug being tested is "the same legitimately-credentialed caller breaks out of the resource subtree." Root / empty paths emit no variants (no trailing segment to reshape). Findings class authz-bypass. Wired into buildRegistry as a always-registered, opt-in mutator (mirrors the cache-deception / prototype-pollution gating pattern).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the
--path-traversalmutator — a focused Phase 2 improvement that closesa real gap in possession's authz-bypass coverage. The operator's task allowed
either
--ssrf-probeor--path-traversal; I verified neither was present(the 17 existing mutators in
internal/mutate/and the 17 flags ininternal/cli/scan.gocover identity/object/forbidden-bypass/host/cookie/header-injection/param-pollution/origin-spoof/ct-confusion/cache-deception/
prototype-pollution/xxe/graphql/mass-assign/method-override/csrf-header/
ws-hijack — no traversal or SSRF). Picked
--path-traversalbecause itfits possession's BOLA/IDOR niche cleanly (it is a resource-scope-escape
mutator, the same vocabulary as
--swap-object/--enumerate/--forbidden-bypass); SSRF is a different niche.What it does
For each eligible captured request (any path beyond
/), emits 18deterministic variants — 6 techniques × 3 high-signal targets — that
replace the trailing path segment with a traversal payload:
dot-dot-slash../../../../../../etc/passwddot-dot-encoded..%2f..%2f...etc/passwd(RawPath keeps%2f)dot-dot-double-encoded..%252f..%252f...etc/passwdnested-dot-dot....//....//...etc/passwdnull-byte-suffix../../...etc/passwd%00absolute-path/etc/passwd(no..at all)Targets:
etc/passwd,proc/self/environ,windows/win.ini.Findings class
authz-bypass(ASVS V12.3). Caller credentials arepreserved on every variant — the bug being tested is "same caller
breaks out of the route prefix." Root paths emit no variants
(no segment to reshape).
Disjointness
--forbidden-bypass(traversal-semicolon): that reshapes thepath to resolve back to the same handler (
/admin/..;/admin);this escapes the resource subtree entirely.
--swap-object/--enumerate: those stay inside the resourcecollection (substitute / sweep known IDs); this breaks out of it.
Wiring
Always registered in
buildRegistry(so the canonical order /allowlist contract is stable); inert when
--path-traversalis notpassed. Mirrors the gating pattern every other off-by-default mutator
uses (
--cache-deception,--prototype-pollution, etc.).Tests
internal/mutate/path_traversal_test.go(18 tests): disabled-by-default,nil-safety, root-skip, credential preservation, full cross-product count,
per-technique wire-form assertions (Path + RawPath + URL.String invariants
for %2f / %252f / %00), determinism, sorted emission, disjointness from
forbidden-bypass, Name() stability, NotInDefaultRegistry, degenerate-inputguards.
internal/cli/buildregistry_forbidden_test.go: addedTestBuildRegistry_PathTraversalGatingTestBuildRegistry_PathTraversalWithWordlistmirroring the cache-deception /prototype-pollution gating tests. Mechanically appended trailing
, falseto every other
buildRegistry()test call for the new signature parameter.Full suite (
go test ./...) andgo vet ./...pass clean.README
New
## Directory / path traversal (--path-traversal)section afterthe prototype-pollution section, with the technique table and the
disjointness paragraph against
--forbidden-bypass/--swap-object.Test plan
go build ./...cleango vet ./...cleango test ./...— all packages greenpossession scan --helpshows the new--path-traversalflag(operator follow-up — outside Worker scope)
🤖 Generated with Claude Code