Post-trust hardening: per-hook visibility, headless mode protections, sandboxing
Summary
The pre-trust-dialog RCE (CVE-2025-59536) and env var exfiltration (CVE-2026-21852) are patched — great work. This issue proposes four post-trust hardening improvements that would reduce the blast radius once a user clicks "Trust Project."
Current Behavior
After a user clicks "Trust Project," all command hooks execute with full shell privileges: unrestricted filesystem, network, and environment access. There is no secondary confirmation, no sandboxing, and no visibility into what hooks will run.
Proposed Improvements
1. Per-hook visibility in the trust dialog
The trust dialog is all-or-nothing. A repo with 20 hooks gets the same single "Trust Project" click as one with zero.
Suggestion: Show which hooks will activate (event types, commands, URLs) in the trust dialog so users can make an informed decision. Similar to how browser extensions show requested permissions before install.
2. Headless mode (-p flag) protections
Trust verification is disabled in non-interactive mode. Anyone running claude -p on untrusted repos (e.g., PR checks on forks in CI/CD) gets zero protection.
Suggestion: In headless mode, either:
- Skip project hooks entirely (safe default)
- Require an explicit
--trust-hooksflag to opt in - Only allow hooks from a pre-approved allowlist
3. Hook sandboxing after trust
After trust, hooks run with the same privileges as the Claude Code process. There's no filesystem restriction, network allowlisting, command allowlisting, or capability dropping.
Suggestion: Even a lightweight sandbox would help — e.g., no outbound network for command hooks by default, or an opt-in "sandbox": true flag that restricts hooks to localhost-only network access.
4. HTTP hooks allowedEnvVars semantics
The allowedEnvVars field in HTTP hooks is defined by the hook author, not the user. This is counterintuitive — users may assume it's a restriction on the hook, but it's actually a whitelist by the hook that controls which env vars get interpolated.
Suggestion: Either:
- Rename to
requestedEnvVarsto clarify semantics - Show the requested vars in the trust dialog for user approval
- Move the allowlist to the user's local settings rather than the project config
Context
We maintain a repo (vgccorner-web) with 6 command hooks in .claude/settings.json for agent observability (forwarding tool-call events to a local dev server). While auditing our own hook config, we identified these hardening opportunities.
Our hooks are benign (curl localhost:3000), but the same pattern could trivially exfiltrate every tool call to a remote server. The trust dialog is the only gate, and it doesn't surface what it's authorizing.
Comparison to Similar Vectors
| Vector | Trigger | Sandboxed? | User Prompt? |
|--------|---------|-----------|--------------|
| Claude Code hooks | Session start / tool use | No | Trust dialog (once) |
| npm postinstall | npm install | No | No (unless --ignore-scripts) |
| .husky/ git hooks | git commit/push | No | No |
| .vscode/settings.json | Open folder | Partial (no exec) | Workspace trust dialog |
| GitHub Actions | Push/PR/schedule | Yes (container) | No (repo permissions) |
Claude Code hooks are comparable to npm postinstall and husky in risk, but fire more frequently (every tool call, not just install/commit).
Related
- CVE-2025-59536 (RCE via SessionStart hooks, patched in v1.0.111+)
- CVE-2026-21852 (API key exfiltration via env redirect, patched in v2.0.65+)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗