Repository navigation
Branch reviews load the reviewed checkout's project settings: hooks, env and CLAUDE.md #117
Description
Updated after testing (see #118). The original version of this issue said the problem was hooks alone, that machines with
disableAllHookswere not exposed, and suggesteddisableAllHooksas the fix. That was wrong. The checkout'senvandCLAUDE.mdload as well, andenvcan run code without any hook. The text below is corrected.
Summary
$cc:review and $cc:adversarial-review start Claude with -p inside a new worktree when they review a branch. The worktree checks out the commit under review, and a print-mode child doesn't ask for trust. Setting sources are not limited, so the checkout's project settings load:
- Hooks in
.claude/settings.json, such asSessionStart, run as soon as the review starts. envreaches the processes the child starts. The review's git MCP server isnode, soenv: {"NODE_OPTIONS": "--require ./.claude/probe.cjs"}runs a file committed in the branch, even withdisableAllHooksset.CLAUDE.mdand.claude/rulesreach the model as instructions. So doesAGENTS.md, which Claude Code 2.1.277 and later reads when a project has noCLAUDE.md.
So a branch under review can run code on the reviewer's machine and steer the reviewer, even though the review allowlist excludes Bash. --allowedTools limits tools, not settings.
Where (v1.5.0)
scripts/lib/review-worktree.mjs:createReviewIsolation/createReviewWorktreecreate the worktree, a detached checkout.scripts/claude-companion.mjs: review and adversarial review runrunClaudeReviewinisolation.cwd.scripts/lib/claude-cli.mjs:buildArgssends-p ... --allowedTools ... --settings <preset>, with no--setting-sources.
Reproduction
Claude Code 2.1.283, macOS. Run the full companion (node scripts/claude-companion.mjs review --cwd <repo> --base main) against a local mock API with a fresh CLAUDE_CONFIG_DIR.
- The repo commits
.claude/settings.json(a SessionStart hook and theNODE_OPTIONSenvabove),.claude/probe.cjsandCLAUDE.mdonmain, then a code change on a feature branch. - On v1.5.0 the hook runs, the probe file runs, and
CLAUDE.mdreaches the model request. - Adding
disableAllHooks: trueto user settings stops only the hook.
Fix
Pass --setting-sources user to review children that run in a worktree. User settings, managed settings and the --settings file still load. Claude Code before 2.1.281 accepts the flag without applying it everywhere: nested .claude/rules files (fixed in 2.1.211), the command sandbox's filesystem configuration (2.1.246) and spawned sessions (2.1.281). Worktree reviews must refuse those versions. #118 does both.
Reviews that run in the user's own repository have the same exposure when an untrusted branch is checked out there:
- Working-tree reviews, which auto scope picks on any local change.
- The stop-review gate, which runs whenever a turn changes the working-tree fingerprint (the index, unstaged changes and untracked files). A turn that only checks out a branch with different content changes the index, so that alone is enough.
#118 leaves those unchanged and explains the trade-off.
Activity
fix(review): load user settings only in review children
fix(review): load user settings only in the review worktree
docs(review): say what the worktree setting sources keep and why
fix(review): refuse worktree reviews on Claude Code older than 2.1.211
[-]Review children run hooks from the reviewed branch's .claude/settings.json[/-][+]Branch reviews load the reviewed checkout's project settings: hooks, env and CLAUDE.md[/+]fix(review): require Claude Code 2.1.281 and a release version for wo…