fix(scan): stop cross-scan leak on single-file scans of configs#54
Merged
jonathansantilli merged 1 commit intomainfrom Apr 22, 2026
Merged
Conversation
PR #53 closed the cross-scan leak for skill-dir scans but not for single-file scans of configs like ~/.claude/settings.json. Symptom: $ codegate-ai scan ~/.claude/settings.json → finding with file_path=~/.agents/skills/api-design-guide/.../SKILL.md Root cause: the CLI stages single-file targets into a temp dir outside $HOME. The staged dir is not inside homeDir, so shouldKeepUserScopeCandidate short-circuits to `return true` and every sibling user-scope match (e.g. a hidden-unicode hit in a completely unrelated skill) gets attributed to the config scan. Fix: - cli.ts: when resolvedTarget.explicitCandidates is non-empty (the target was a staged local file), force scan_user_scope=false for that scan. Explicit opt-in via --include-user-scope still overrides. This matches user expectation: "scan this file" ≠ "scan my whole home." - scan.ts: shouldKeepUserScopeCandidate now also handles engine-level file targets correctly (if the target is a file inside homeDir, only the target file itself is a valid user-scope candidate). This is defence in depth for library callers that bypass the CLI. Tests: - Existing 3 cases in tests/layer2/cross-scan-attribution.test.ts still pass. - New: engine-level file-target scan drops sibling user-scope candidates. Verified 154 test files / 720 tests pass. Lint + prettier clean.
github-actions Bot
pushed a commit
that referenced
this pull request
Apr 22, 2026
## [0.14.3](v0.14.2...v0.14.3) (2026-04-22) ### Bug Fixes * **scan:** disable user-scope walk when CLI scans a single file ([#54](#54)) ([6799651](6799651))
jonathansantilli
added a commit
that referenced
this pull request
Apr 22, 2026
#55) PR #54 disabled the user-scope walk when the CLI scanned a single local file, by gating on `explicitCandidates.length > 0`. That gate breaks for files whose extension is not in `inferTextLikeFormat` — e.g. `.idea/workspace.xml`, `.env` with unusual names, binary-ish configs — because `collectExplicitCandidates` returns `[]` for them, the guard never fires, and sibling user-scope findings (e.g. a hidden-unicode hit in `~/.agents/skills/foo/SKILL.md`) leak into the scan of the unrelated file. Reproducer (0.14.3): $ npx codegate-ai scan ~/workspace/.idea/workspace.xml --format json scan_target: .../.idea/workspace.xml findings: - HIGH rule-file-hidden-unicode file_path: ~/.agents/skills/api-design-guide/domains/rest/SKILL.md ## Fix Add a `stagedFromLocalFile: true` flag to `ResolvedScanTarget`, set from `stageLocalFile`. The CLI gate now uses this flag directly: scan_user_scope = --include-user-scope ? true : stagedFromLocalFile ? false : baseConfig.scan_user_scope It's a signal that doesn't depend on whether the file's extension was recognisable. Covers every file type, no per-format maintenance. ## Tests `tests/scan-target.test.ts`: - Staged `.xml` file gets `stagedFromLocalFile=true` AND empty `explicitCandidates` (the PR #54 gate would have failed here). - Staged `.json` file also gets `stagedFromLocalFile=true` and populated `explicitCandidates` — no regression on the happy path. All 155 files / 722 tests pass. Lint + prettier + typecheck clean.
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
Closes the remaining cross-scan leak left open by #53. Scanning a single file under
$HOME(e.g.~/.claude/settings.json) still surfaced findings from unrelated siblings like~/.agents/skills/*/SKILL.md.Reproducer (0.14.2)
The finding doesn't belong to that scan.
Root cause
The CLI stages single-file targets via
stageLocalFile, which copies them into a temp dir (outside$HOME). The scan engine then runs against the staged temp dir. InshouldKeepUserScopeCandidate:scanTarget=/tmp/codegate-scan-target-xxxhomeDir=/Users/meisPathInside(homeDir, scanTarget)= falsetruefor every candidate$HOMEleaks every hidden-unicode match back into the scan#53 scoped its fix to scan targets inside
homeDir. Staged file targets aren't insidehomeDir, so they skipped the fix.Fix
CLI layer (primary): when
resolvedTarget.explicitCandidatesis non-empty (i.e. the raw target was a local file, now staged), forcescan_user_scope = falsefor that scan. Explicit opt-in via--include-user-scopestill overrides. This matches user expectation: "scan this file" ≠ "scan my whole home."Engine layer (defence in depth):
shouldKeepUserScopeCandidatenow also handles engine-level file targets. If the target is a file insidehomeDir, only the file itself is a valid user-scope candidate. Library callers bypassing the CLI get the same guarantee.Tests
tests/layer2/cross-scan-attribution.test.ts:Checks
npm run typecheck✅npm run lint✅npm test— 154 files / 720 tests (+1 from fix(scan): stop attributing host-wide findings to per-target scans #53)npx prettier --check✅Key files
src/cli.ts— CLI-layer fixsrc/scan.ts— engine-layer fix (shouldKeepUserScopeCandidate)tests/layer2/cross-scan-attribution.test.ts— new engine-level file-target test