Classify dev-env auto-exec paths as sensitive and broaden .envrc#134
Merged
Classify dev-env auto-exec paths as sensitive and broaden .envrc#134
Conversation
Modern dev tooling has a handful of files whose contents are
executed by routine developer actions — IDE opening, `npm install`,
`pip install`, `cd` into a direnv-managed dir. Previously none of
these were flagged, so an agent in auto-accept mode could quietly
plant malicious scripts that the host user would run on their next
unrelated workflow step.
Changes:
- `.envrc` changes from exactRootRule to basenameRule AND from
TierAutoExec to TierBuildCI. direnv walks upward from the user's
shell cwd, so a subdir `.envrc` fires on `cd sub/` — same auto-
exec surface as the root case. The tier downgrade reflects that
direnv itself gates execution behind `direnv allow` after each
`.envrc` change (user-action-required), making this consistent
with how `package.json` scripts require `npm install`. Keeping
Tier 1 would have destroyed agent work on direnv-heavy monorepos
because a rejected flush discards the entire session's changes.
- New Tier 2 (warn-but-flush) entries for the genuinely exec-
surfaced dev files only, staying targeted to avoid noisy warnings
on routine edits:
- `.vscode/tasks.json` and `.vscode/launch.json` — execute on
F5 / Run Task (skipped: settings.json / extensions.json which
carry no exec surface).
- `.devcontainer.json` and `.devcontainer/devcontainer.json` —
lifecycle commands execute on Reopen in Container (skipped:
other files in .devcontainer/ which users edit routinely).
- `package.json` — scripts.{pre,post}{install,prepare,…} execute
on npm/yarn install. Basename so monorepo per-package manifests
are caught too.
- `pyproject.toml`, `setup.py` — script hooks execute on pip /
poetry install.
New helper `pathSuffixRule` does separator-aware suffix matching so
`.vscode/tasks.json` at any depth matches while `foo.vscode/tasks.json`
(a filename ending with ".vscode") correctly does not.
UX: the auto-accept reviewer's per-file REJECTED line now embeds the
"re-run with --review to approve" hint directly, so users who hit a
Tier 1 rejection see the recovery path on the same line without
having to scroll to the summary footer.
Co-Authored-By: Claude Opus 4.7 (1M context) <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.
Summary
Closes a MEDIUM finding: modern dev tooling has files whose contents are executed by routine developer actions (
npm install,pip install,direnv allow && cd, F5 in VSCode, Reopen in Container). An agent in auto-accept mode could quietly plant malicious scripts in these files — they'd flush back to the host and run on the user's next unrelated workflow step.Changes
New Tier 2 (warn-but-flush) sensitive-path entries, narrowly targeted to actual exec surfaces:
.vscode/tasks.json.vscode/launch.json.devcontainer.json,.devcontainer/devcontainer.jsonpackage.json(basename)npm install/yarn installscriptspyproject.toml(basename)pip install/poetry installhookssetup.py(basename)pip install ./python setup.py.envrc(basename)direnv allow && cdDeliberately skipped to avoid noise on routine edits:
.vscode/settings.json,.vscode/extensions.json— no exec surface.devcontainer/Dockerfileand other.devcontainer/*non-entrypoints.idea/— JetBrains UI statepackage-lock.json,poetry.lock)UX trade-offs
Every new entry is Tier 2 (warn, still flush). Tier 1 would have broken Node/Python workflows because agents routinely edit
package.json,pyproject.toml, etc. as part of legitimate work. The stderr warning surfaces the concern without blocking..envrcre-tiered from 1 → 2Pre-patch: Tier 1 (auto-reject). Post-patch: Tier 2 (warn-but-flush). Rationale:
direnv allowafter every.envrcchange — a user-action-required step, same risk profile asnpm installtriggeringpackage.jsonscripts..envrc— particularly painful in direnv-heavy monorepos (Nix, Rust, Ruby).exactRootRuletobasenameRulefor correctness: direnv walks upward, so a subdir.envrcfires oncd sub/.REJECTED line now self-documents recovery
REJECTED: <path> — <reason> (re-run with --review to approve)instead of requiring the user to read the summary footer. Any remaining Tier 1 rejection (e.g..git/hooks/) prints the recovery hint on the same line as the file name.New helper
pathSuffixRuledoes separator-aware suffix matching —.vscode/tasks.jsonat any depth matches, butfoo.vscode/tasks.json(filename ending with ".vscode") correctly does NOT.Test plan
task fmt && task lint && task test— all greenTestClassifyPathcoverage: every new entry at workspace root + monorepo-nested path + negative controls (settings.json, Dockerfile, lockfiles,foo.vscode/tasks.jsonfalse-positive)TestAutoAcceptReviewer_MixedTiersupdated for the.envrcre-tierpackage.json+.vscode/tasks.json+README.md; agent edits all three; stderr shows two WARNINGs (package.json, tasks.json); all three files flush; VM cycles cleanFollow-ups (not this PR)
Gemfile,Rakefile) and Rust (build.rs) install-time exec surfaces — same class, deferred.package.jsonedits → 10 warnings. Could dedup in the summary.🤖 Generated with Claude Code