Repository navigation
permissions: cover MCP/hook process-source configs and trailing-dot variants in is_sensitive_path - #271
Conversation
|
@Zongwei9888 — this PR touches the sensitive-path denylist and a CVE-2026-103572-class normalization bypass, so it needs a security review. A fork can't set the Summary for the reviewer:
|
|
Thank you, @raymondginger2018-sudo. The trailing-dot part is right: Windows drops trailing dots and spaces from path components when it opens a file, so The new patterns need to change before we can merge:
A version we'd merge: the trailing-dot probe as it is, plus a check that turns a file-tool write to one of the three hook files into an |
The three hook-discovery files (user and workspace hooks.json, workspace .claude/settings.json) are not secrets: reads stay free. A written-in handler runs commands in a later session, so a file-tool write that would otherwise be allowed becomes an ask; stricter decisions (deny rules, plan mode, the read-only preset) are never relaxed, and no allow rule can silence the confirmation. Also match sensitive paths through Windows trailing dots and spaces, which the OS drops at open time while normpath keeps them: a stripped probe variant is checked alongside the literal path (the reported path stays as written).
8c88f38 to
b25569f
Compare
|
@Zongwei9888 — rewritten as the version you described, pushed as
Tests cover both directions: writes ask even in Local preflight of this exact head (Windows, Python 3.12/3.13/3.14): no new failures; only the already-tracked Windows-only lifecycle/desktop flakes. |
|
Thank you for the quick rewrite, @raymondginger2018-sudo. This is the shape we asked for: reads stay free, the trailing-dot probe is kept, and stricter decisions keep their strength. One change before merge. Full Access. Full Access resolves to Please skip this check under Full Access, the same way Full Access skips the sensitive-path guard and origin approval ( |
What
Two targeted hardenings in
core/harness/permissions.py, both about the path-matching layer:Protect MCP/hook process-source configs. Adds 5 names to
SENSITIVE_PATH_PATTERNS:.mcp.json,mcp_servers_canonical.json,.deepcode/settings.json,.claude/settings.json,.deepcode-plus/settings.json.These files decide which external processes the next session spawns (MCP stdio servers,
workspace hooks), so a written-in server definition is delayed code execution; the generated
sync copies also carry plaintext env-derived keys. They belong in the same protected class
as
.env/.netrcalready on the list, and they are script-maintained outside the agenttool path, so denying tool-path access breaks no legitimate in-session workflow.
Match through trailing dots/spaces (CVE-2026-103572-class bypass). Windows drops
trailing dots and spaces from path components at open time while
os.path.normpathkeepsthem — the literal name
.mcp.json.opens.mcp.json, yet a literal compare misses it.is_sensitive_pathnow also probes per-componentrstrip(" .")variants (with./..components protected). The strip is match-only: the reported path stays as written.
Why
file tools under any permission mode.
as-written form is what CVE-2026-103572 exploited upstream of this pattern family.
Tests
3 new regression tests (red → green):
.vscode/settings.jsonor plain JSON files.Local run on Windows git-bash:
tests/test_harness_permissions.py38 passed. Thepre-existing
test_denylist_follows_symlinksfails locally withWinError 1314(symlinkprivilege) — that test exists unchanged on
mainand is environmental, not introduced here.Security Considerations
is_sensitive_path) for 5 explicit confignames; no exec/sandbox control-flow change, patterns are data-only additions.
logs and error messages keep the user-visible name.
tool path (that is the point for generated plaintext-key-bearing copies).