Skip to content

fix(cli-claude): stop rewriting Bash commands in PreToolUse auth-scrub hook#202

Open
danljungstrom wants to merge 1 commit into
happier-dev:devfrom
danljungstrom:fix/claude-auth-hook-command-mutation
Open

fix(cli-claude): stop rewriting Bash commands in PreToolUse auth-scrub hook#202
danljungstrom wants to merge 1 commit into
happier-dev:devfrom
danljungstrom:fix/claude-auth-hook-command-mutation

Conversation

@danljungstrom

@danljungstrom danljungstrom commented Jul 16, 2026

Copy link
Copy Markdown

Summary

Removes the Bash command rewrite from the Claude Agent SDK PreToolUse auth-scrub hook. Auth-token isolation stays enforced via subprocess env scrubbing; the hook no longer mutates commands before Claude Code's permission layer sees them.

Why

The hook prepended an unset ANTHROPIC_API_KEY ...; prelude to every Bash command, which:

  • broke Bash prefix allow rules (e.g. Bash(gh:*)), since the rewritten command no longer started with the allowed prefix
  • triggered auto-mode "unsetting auth tokens" denials for benign commands
  • spammed mobile permission prompts showing the preamble instead of the real command

The rewrite added no protection beyond the existing env scrub: subprocess env is already sanitized by isolateClaudeRuntimeAuthEnv / buildClaudeSubprocessEnv, and shell snapshots capture only PATH.

How to test

  1. cd apps/cli && yarn vitest run src/backends/claude/remote/claudeRemoteAgentSdk.optionsAndHooks.test.ts — hook tests assert Bash commands pass through unmodified and env scrubbing still applies.
  2. cd apps/cli && yarn typecheck
  3. Manual: start a Claude session through the Happier daemon with a Bash(gh:*) allow rule in .claude/settings.json; run a gh command and confirm it is auto-allowed without a permission prompt (previously denied/prompted because the command was rewritten).
  4. Manual: verify ANTHROPIC_API_KEY set in the daemon environment is still absent from the spawned Claude subprocess env.

Screenshots / recording (UI changes)

N/A — CLI-only change.

Notes (optional)

Security: no weakening of auth isolation. The command mutation was a redundant second layer on top of subprocess env scrubbing, and it broke permission-rule matching as a side effect. Changed files:

  • apps/cli/src/backends/claude/remote/agentSdk/buildClaudeAgentSdkHooks.ts — remove Bash command mutation
  • apps/cli/src/backends/claude/remote/claudeRemoteAgentSdk.optionsAndHooks.test.ts — update hook tests to assert pass-through

Checklist

  • PR targets dev (not main)
  • I linked an issue/discussion (recommended for non-trivial changes)
  • I added/updated tests where feasible (or explained why not)
  • I updated docs if behavior changed (no doc surface documents the hook prelude)
  • If AI-assisted, I disclosed it and listed what I personally verified

AI-assisted (Claude Code). Verified by running the updated hook test file and CLI typecheck locally.

🤖 Generated with Claude Code

…b hook

The Agent SDK PreToolUse hook prepended an `unset ANTHROPIC_API_KEY ...;`
prelude to every Bash command before Claude Code's permission layer saw it,
which broke Bash prefix allow rules (e.g. `Bash(gh:*)`), triggered auto-mode
"unsetting auth tokens" denials for benign commands, and spammed mobile
permission prompts showing the preamble instead of the real command.

Auth-token isolation remains enforced via subprocess env scrubbing
(isolateClaudeRuntimeAuthEnv / buildClaudeSubprocessEnv); shell snapshots
capture only PATH, so the command rewrite added no protection beyond the
env scrub.

Co-Authored-By: Claude Fable 5 <[email protected]>
@greptile-apps

greptile-apps Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR removes the PreToolUse hook in buildClaudeAgentSdkHooks.ts that prepended an unset ANTHROPIC_API_KEY ...; preamble to every Bash command before Claude Code's permission layer saw it. Auth-token isolation is preserved through buildClaudeSubprocessEnvisolateClaudeRuntimeAuthEnv, which already scrubs the sensitive keys from the Claude subprocess environment before any tool runs.

  • Removed command rewrite — the PreToolUse hook that mutated tool_input.command is deleted, so Bash commands reach the permission layer byte-identical to what the model generated, fixing broken prefix allow rules (e.g. Bash(gh:*)) and spurious auto-mode classifier denials.
  • Tests updated — the old assertions that the rewritten command contained unset and specific token names are replaced with a single expect(capturedOptions.hooks.PreToolUse).toBeUndefined() assertion, with an inline comment explaining why the rewrite was harmful.

Confidence Score: 5/5

Safe to merge. The removed hook was actively breaking Claude Code's permission layer and the auth isolation path it replicated is already in place at the subprocess env level.

The deletion is narrow and well-targeted: only the PreToolUse mutation block is removed, the SessionStart and PermissionRequest hooks are untouched, and the subprocess env scrubbing (buildClaudeSubprocessEnv → isolateClaudeRuntimeAuthEnv) already removes all platform auth keys before Claude Code starts. In connected-service mode every key in CLAUDE_AUTH_ENV_KEYS is wiped from the subprocess env, making the shell-level unset genuinely redundant. Tests cleanly verify the absence of the hook and provide a clear rationale in comments.

No files require special attention.

Important Files Changed

Filename Overview
apps/cli/src/backends/claude/remote/agentSdk/buildClaudeAgentSdkHooks.ts Removes the entire PreToolUse hook block that prepended unset ...; to Bash commands and drops the now-unused CLAUDE_AUTH_ENV_KEYS import; the remaining SessionStart and PermissionRequest hooks are untouched.
apps/cli/src/backends/claude/remote/claudeRemoteAgentSdk.optionsAndHooks.test.ts Two test cases updated: one asserts PreToolUse is absent on the captured hooks object; the other replaces the previous behavioural assertions on the rewritten command string with the same absence check, and both add explanatory comments.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant M as Claude Model
    participant SDK as Agent SDK
    participant Perm as PermissionRequest Hook
    participant Env as Subprocess Env Scrubber
    participant Bash as Bash Tool

    rect rgb(255, 220, 220)
        Note over SDK: BEFORE - PreToolUse rewrites command
        M->>SDK: Bash tool_use gh pr list
        SDK->>SDK: PreToolUse prepends unset AUTH_KEYS prelude
        Note over SDK: Bash prefix allow rule no longer matches
        SDK->>Perm: PermissionRequest with rewritten command
        Perm-->>SDK: decision
        SDK->>Bash: execute rewritten command
    end

    rect rgb(220, 255, 220)
        Note over SDK: AFTER - no PreToolUse hook
        M->>SDK: Bash tool_use gh pr list
        SDK->>Perm: PermissionRequest with original command
        Note over Perm: Prefix allow rule matches correctly
        Perm-->>SDK: allow
        SDK->>Env: buildClaudeSubprocessEnv
        Note over Env: Auth keys scrubbed from subprocess env
        SDK->>Bash: execute original command in clean env
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant M as Claude Model
    participant SDK as Agent SDK
    participant Perm as PermissionRequest Hook
    participant Env as Subprocess Env Scrubber
    participant Bash as Bash Tool

    rect rgb(255, 220, 220)
        Note over SDK: BEFORE - PreToolUse rewrites command
        M->>SDK: Bash tool_use gh pr list
        SDK->>SDK: PreToolUse prepends unset AUTH_KEYS prelude
        Note over SDK: Bash prefix allow rule no longer matches
        SDK->>Perm: PermissionRequest with rewritten command
        Perm-->>SDK: decision
        SDK->>Bash: execute rewritten command
    end

    rect rgb(220, 255, 220)
        Note over SDK: AFTER - no PreToolUse hook
        M->>SDK: Bash tool_use gh pr list
        SDK->>Perm: PermissionRequest with original command
        Note over Perm: Prefix allow rule matches correctly
        Perm-->>SDK: allow
        SDK->>Env: buildClaudeSubprocessEnv
        Note over Env: Auth keys scrubbed from subprocess env
        SDK->>Bash: execute original command in clean env
    end
Loading

Reviews (1): Last reviewed commit: "fix(cli-claude): stop rewriting Bash com..." | Re-trigger Greptile

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The Claude Agent SDK no longer rewrites Bash commands through a PreToolUse hook. Related OAuth forwarding and regression tests now assert that the hook is not registered.

Changes

Claude hook removal

Layer / File(s) Summary
Remove Bash preprocessing and update coverage
apps/cli/src/backends/claude/remote/agentSdk/buildClaudeAgentSdkHooks.ts, apps/cli/src/backends/claude/remote/claudeRemoteAgentSdk.optionsAndHooks.test.ts
The Bash-specific PreToolUse hook and auth-environment rewriting are removed, while tests assert that PreToolUse is undefined.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: leeroybrun

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the main change: removing Bash command rewriting from the PreToolUse auth-scrub hook.
Description check ✅ Passed The description follows the template and includes summary, rationale, testing steps, screenshots, notes, and checklist items.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant