Repository navigation
File paths: refuse a leading env reference, name the place it means - #391
Merged
Merged
Conversation
There was a problem hiding this comment.
If your organization's extra usage balance is empty, an organization admin can add extra usage credits at claude.ai/admin-settings/usage. If its monthly spend limit was reached, an admin can raise it on the same page. If neither applies, contact Anthropic support.
Once extra usage is available, someone with write access to this repository can comment @claude review on this pull request to trigger a review.
Nothing on the way to a file tool is a shell, so "$env:USERPROFILE\.gitconfig"
was joined onto the workspace as a literal "$env:USERPROFILE" directory:
the read failed on a path the model never wrote, after the risk check had
scored (and the user approved) the home directory it meant.
Resolve now expands a leading $env:NAME, ${NAME}, $NAME or %NAME% to its
value, and ~\ on Windows like ~/. Only a variable that is set, and only
when a separator or the end follows — "Foo$Bar.class" and "$Recycle.Bin"
are file names. The jail and the deny floor run on the expanded path.
Fixes #389.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
rromenskyi
force-pushed
the
file-path-env-refs
branch
from
October 20, 2026 00:27
a041184 to
b9dd4f1
Compare
Review found expanding one was a way to read a secret: "$OPENAI_API_KEY"
as a read path resolved to <workspace>/sk-…, and the "no such file" error
handed the key to the model, with no prompt. It also let a call open
something other than what the approval prompt, the risk check and git had
seen.
Resolve now refuses such a path with "file paths are not shell-expanded —
pass the full path", naming the value only for a place (HOME, USERPROFILE,
APPDATA, TEMP, …) so the model can retry at once. Any other variable's
value never appears. PowerShell's env: matches in any case, and
${env:NAME} counts too. ~\ on Windows still expands, like ~/.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A name's case is folded only on Windows: on Unix "home" is its own
variable, and its value was named as if it were HOME's.
- A backslash after the reference counts as a separator on every system:
models write "$env:USERPROFILE\.gitconfig" on macOS too.
- ${env:ProgramFiles(x86)} matches, like %ProgramFiles(x86)%.
- git passes the refusal on, hint included, instead of calling the path
outside the workspace.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Fixes #389.
The path never passes through a shell on its way to a file tool. So
$env:USERPROFILE\.gitconfigwas joined onto the workspace as a literal$env:USERPROFILEdirectory, and the read failed on a path the model never wrote. Before that, the risk check had scored, and the user had approved, the home directory the model meant.The fix is to refuse such a path, not to expand it. The first version of this PR expanded the reference. Review showed that this was a way to read a secret. Reading
$OPENAI_API_KEYresolved to<workspace>/sk-…, and the "no such file" error handed the key to the model with no prompt. Expanding also let a call open something other than what the approval prompt, the risk check and git had all seen.policy.Engine.Resolvenow refuses a path that starts with$NAME,${NAME},$env:NAMEor${env:NAME}(PowerShell'senv:in any case), or%NAME%. The error reads:path "…" starts with $env:USERPROFILE, but file paths are not shell-expanded — pass the full path ($env:USERPROFILE is C:\Users\…).Foo$Bar.class,$Recycle.Binand$HOME.bakstay file names.~\on Windows now expands like~/does.The refusal happens in
Resolve, before any prompt, and it covers file, run cwd, git paths and/cd.Tests:
TestResolveRefusesALeadingEnvReferencechecks every spelling, that a secret's value never appears, and that the non-reference names still work. A sabotage pass made 7 mutations: no refusal, the hint leaking any variable, no separator check, case-sensitiveenv:, no braced env form, no hint, no cmd form. Every one failed the test.🤖 Generated with Claude Code