Skip to content

Branch reviews load the reviewed checkout's project settings: hooks, env and CLAUDE.md #117

Description

@seungpyoson

Updated after testing (see #118). The original version of this issue said the problem was hooks alone, that machines with disableAllHooks were not exposed, and suggested disableAllHooks as the fix. That was wrong. The checkout's env and CLAUDE.md load as well, and env can 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 as SessionStart, run as soon as the review starts.
  • env reaches the processes the child starts. The review's git MCP server is node, so env: {"NODE_OPTIONS": "--require ./.claude/probe.cjs"} runs a file committed in the branch, even with disableAllHooks set.
  • CLAUDE.md and .claude/rules reach the model as instructions. So does AGENTS.md, which Claude Code 2.1.277 and later reads when a project has no CLAUDE.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 / createReviewWorktree create the worktree, a detached checkout.
  • scripts/claude-companion.mjs: review and adversarial review run runClaudeReview in isolation.cwd.
  • scripts/lib/claude-cli.mjs: buildArgs sends -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 the NODE_OPTIONS env above), .claude/probe.cjs and CLAUDE.md on main, then a code change on a feature branch.
  • On v1.5.0 the hook runs, the probe file runs, and CLAUDE.md reaches the model request.
  • Adding disableAllHooks: true to 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions