Inline @-mentioned files outside the workspace instead of blocking them - #365
Merged
Conversation
TheGreatAxios
force-pushed
the
cl-5479-path-grants
branch
from
August 7, 2026 08:16
4e0a91b to
74a245e
Compare
An @-mention is the operator asking the agent to read one path, once, right now — the same consent that already covers workspace files. Outside-workspace mentions now resolve and inline like any other mention, gated only by the sensitive-path and size checks that already applied. Nothing about the mention persists past that one read: no grant is minted, nothing is written to settings, and later reads of the same path still go through the permission gate on its own terms.
@-mentioning a file outside the workspace now inlines it, so the workspace boundary no longer stands between an outside path and the sensitivity check — that check has to carry the full weight alone. Add shell histories, /etc/shadow and /etc/sudoers, macOS Keychain databases, browser cookie jars and saved-login stores, and cloud credential files beyond AWS (gcloud config dir, Azure CLI cache).
TheGreatAxios
force-pushed
the
cl-5479-path-grants
branch
from
August 7, 2026 08:29
74a245e to
7cc2d24
Compare
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
An @-mention of a file or directory outside the workspace now resolves and inlines its content — gated by the sensitive-path (
.env, keys, credential stores, etc.) and size checks — instead of being hard-blocked with "outside workspace". Everything else about the permission gate is untouched.This started as a larger change (a persistent read grant minted on mention) but a security review found the durable half unfit to ship: a working TOCTOU (grant coverage re-resolved the path via
realpathon every check instead of trusting the mint-time path, so swapping the granted directory for a symlink after minting silently redirected the grant), recursive silent-permanent scope from directory mentions, no UI to see or revoke a grant, leakage into unattendedexecruns, a second hand-rolled allow surface parallel to the existing@intx/authzapprovals store, and a settings.json read-modify-write race. All of that was deleted. What ships here is the reduction: a mention inlines a file once, the same consent that already covers workspace files, and authorizes nothing beyond that single read — no state persists, no later read is affected.Why the sensitive-path list had to be extended
The workspace boundary used to be doing double duty. Before this change, a hard-coded "outside workspace" block caught any escape before
isSensitivePathwas ever consulted, so gaps in that list didn't matter for outside-workspace paths. Now that the boundary no longer applies to mentions,isSensitivePathis the only thing standing between an operator typing@~/.bash_historyand its contents landing in the model's context. A live check against the list as it existed found two working leaks:~/.bash_historyand/etc/shadowboth inlined unblocked (.env,.ssh/id_rsa, and.aws/credentialsalready blocked correctly).Extended
SENSITIVE_PATTERNSinsrc/plugins/secret-guard-plugin.ts— reasoning per category:.bash_history,.zsh_history,.sh_history,fish_history): operators paste secrets into interactive shells constantly (export TOKEN=…,curl -H "Authorization: …", a password on apsqlcommand line); the history file is a durable log of exactly that./etc/shadow,/etc/sudoers(.d/*): not API-key secrets, but password hashes and the privilege-escalation policy — direct system-compromise material once reachable.Library/Keychains/,*.keychain[-db]): every saved Wi-Fi password, site login, and app credential on the machine.Cookies,Login Datafor Chrome/Chromium/Edge;cookies.sqlite,logins.json,key4.dbfor Firefox): a cookie store alone is often enough to hijack an authenticated session without ever seeing a password..config/gcloud/directory (legacy_credentials/,credentials.db, etc. live alongside the one file that was already covered), and added Azure CLI's credential cache (.azure/accessTokens.json,.azure/azureProfile.json) — the Azure equivalent of the already-covered~/.aws/credentials.Deliberately left out: full browser history (
places.sqlite) and GPG keyrings beyond what.gnupg/(already covered) catches — out of the "cookie/login-data" and "credential file" scope actually requested, and each would need its own justification.Every new pattern class has both a positive test (the file gets blocked) and, where a plausible false-positive existed, a negative test (e.g.
src/etc/shadow-dom.ts,src/gcloud-deploy.ts,docs/bash_history_format.mdall still resolve normally). Live-verified: the exact.bash_historyand/etc/shadow-shaped leaks reported are now blocked with no content in the output.Tests added
src/plugins/secret-guard-plugin.test.ts: one positive + one adjacent negative case per new pattern class.tests/unit/tui/at-mention-resolution.test.ts: a symlink whose target is both outside the workspace and sensitive (@looks-like-a-normal-file→ symlink → outside-workspaceid_rsa) — the existing symlink test only covered a sensitive target inside the workspace, and the outside-workspace sensitivity test only covered a direct (non-symlink) path. This combination was previously unverified by any test.src/permission/path-restriction.test.ts: kept the prefix-sibling regression (/tmp/xvs/tmp/xbaz) as aresolveWorkspacePath/workspace-boundary test, since that property still matters independent of the deleted grant system.What I verified by running
bun run typecheck,bun run build,bun run testall pass (4037 tests, 0 failures)..bash_historyunder a fake$HOME, and anetc/shadow-shaped path with fabricated hash content) — both now return(blocked: sensitive path)with zero leaked content in the resolved text.read_filecall against that same path on a fresh permission gate still prompts the operator and is denied when declined — confirming no standing grant survives the mention (the one-shot property is structural:resolveAtMentionsnever calls intopath-restriction.ts,gate.ts, oradmin.ts).