Skip to content

fix(security): the leak gate missed three of four Windows spellings of the home path - #174

Closed
wshallwshall wants to merge 1 commit into
mainfrom
claude/leakgate-home-path-casing
Closed

fix(security): the leak gate missed three of four Windows spellings of the home path#174
wshallwshall wants to merge 1 commit into
mainfrom
claude/leakgate-home-path-casing

Conversation

@wshallwshall

Copy link
Copy Markdown
Collaborator

Implements BACKLOG #325. All four Windows spellings of the home path now fire; /users/ still misses, deliberately, and that is now asserted rather than left to be rediscovered.

The item's own warning was re-measured independently rather than repeated: a naive whole-pattern re.I produces 48 hits across 1,956 tracked files, versus 0 for the shipped inline form. The item records 47 — the one-hit gap is this measurement running after the patch, whose new comment adds a c:\users example. Not a discrepancy in the item's number, and worth stating so nobody "reconciles" it later.

The docs/BACKLOG.md edit is load-bearing, not cosmetic

Making the slug pattern case-insensitive causes it to match exactly one line in the tracked tree — #325's own prose, which spelled out a literal upper-cased example slug. Left alone, the very first run of the required forbidden-content context would go red on the item describing the fix. The two-line rewrite keeps the example descriptive instead of literal.

That is a nice illustration of the class: a detector that becomes correct starts matching the documentation that described its blindness.

Verification

Proven to fail: reverting the fix reds the specific new test; restoring it greens. Touches no ranked-table row, no tier count and no census line — checked with an anchored pattern after a first attempt at that check was itself broken.

#325)

The forbidden-content gate is a REQUIRED merge context. Its home-path detector
class-matched the drive letter but treated `Users` as a literal, so of four spellings
of the same case-insensitive Windows directory only the canonical one fired:

    C:\Users\<acct>\proj   FIRES        c:/users/<acct>/proj   missed
    c:\users\<acct>\proj   missed       C:\USERS\<acct>\proj   missed

Same account, same disclosure, three of four spellings walking through a required gate.

THE OBVIOUS FIX IS THE WRONG ONE, AND THE ITEM SAYS SO. A whole-pattern re.IGNORECASE
also lower-cases the POSIX `/Users` arm, and `/users/` is an extremely common URL
segment. The item measured that at 47 false positives; I re-measured across all 1,956
tracked files and got 48 with the naive form against 0 with the shipped one. (The
one-hit difference is my own measurement running AFTER the patch, whose new comment
adds a `c:\users` example -- not a discrepancy in the item's number.) So the fold is
INLINE and scoped to the drive-letter alternative only.

Verified behaviour, all ten cases:
  all four Windows spellings           FIRE
  /home/<acct>, /Users/<acct>          FIRE (unchanged)
  /users/<acct>                        MISSES -- load-bearing, and now asserted
                                       deliberately so nobody "fixes" it into the
                                       47-false-positive form
  Public/runner/user stand-ins         still exempt (exemption list untouched)

`_WORKTREE_SLUG` was case-blind the same way and is taken in the same change, per the
item's point 5. Reachable: scripts/worktree/new.ps1 accepts `[A-Za-z0-9._-]+` and
lowercases nothing.

THE docs/BACKLOG.md EDIT IS NOT COSMETIC. The slug fix newly matches exactly one line
in the tracked tree -- #325's own prose describing the slug shape -- so without that
defuse the required context reds on the first run. Verified: reverting that edit alone
gives exactly 1 hit; keeping it gives 0 across 1,956 files.

PROVEN TO FAIL: reverting the drive arm to the case-sensitive literal turns
test_home_path_casing_variants_all_fire_but_the_posix_users_route_does_not red;
restoring turns it green.

Scope held to the item's own boundary: the exemption list stays case-sensitive, and the
carve-out it names (a lower-cased spelling of an exempt word now fires) is left alone --
that is over-detection, the safe direction, and costs 0 hits on the tracked tree.

Two local hits remain under `--path .` from the POSIX arms, in an untracked, gitignored
file. Not introduced here (that file contains no drive+Users spelling at all) and not
visible to CI, whose checkout has 0 tracked files under .claude/.

66 tests pass; ruff clean; 0 tracked-tree hits.
@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Superseded by #177, which batches this with the other two small code changes into one CI cycle.

Nothing is dropped — this commit is carried across verbatim in #177. Closing rather than leaving it open because strict: true makes every open PR pay a full ~32-minute re-run each time anything else merges, so N open code PRs cost ~N sequential cycles. Three separate PRs was ~96 minutes of serialised draining for ~290 lines; batched it is one cycle. #175 had already gone DIRTY from that pressure.

🤖 Batched by Claude Code

auto-merge was automatically disabled August 4, 2026 14:09

Pull request was closed

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.

1 participant