Post-trust hardening: per-hook visibility, headless mode protections, sandboxing

Resolved 💬 3 comments Opened Mar 5, 2026 by Vgccorner Closed Apr 6, 2026

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-hooks flag 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 requestedEnvVars to 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+)

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗