Claude Code hooks and permissions: what a pull request can grant an agent
A coding agent's power is configured in files that sit next to your code. A one-line change to .claude/settings.json can make an agent run a command on every session, or stop asking before it runs any shell command at all.
Where a coding agent's authority is configured
Claude Code, Codex, Gemini CLI, Cursor, and similar tools read project files to decide what the agent may do. In Claude Code, .claude/settings.json holds hooks (commands that run on events such as SessionStart or PostToolUse) and permission rules (which tools run without asking). Skills, subagents, plugins, and marketplaces add more, and a CI workflow that runs the agent adds the permissions of that job's token.
Because these files travel with the repository, anyone who can open a pull request can propose a change to what every developer's agent does.
Changes that matter, and how they look in a diff
Each of these is a small diff with a large effect:
- A new SessionStart hook: a command that runs every time anyone opens the project with the agent.
- A widened allow rule, such as Bash(*): the agent runs any shell command without asking.
- A bypass or auto-approve mode: the agent stops asking for confirmation at all.
- A new MCP server or plugin from an unpinned source.
- A workflow that runs the agent with write access to the repository or cloud credentials.
Why this is a real attack path
In August 2025, a compromised release of the Nx build tool's npm packages ran a script that invoked AI coding CLIs installed on developers' machines with flags that skipped their permission prompts, and used them to search for secrets. Attackers already know that a coding agent with relaxed permissions is a capable tool on a developer's laptop.
Gate agent configuration like code
ControlLoop reads the coding agent's configuration in your repository and reports each change as a statement a reviewer can act on: this change gives Claude Code the power to run node .github/setup.js on every session start. The same deterministic gate that blocks a risky tool change blocks a risky hook, and a recorded approval in controlloop.yaml turns a known, reviewed change from a block into a note.
Everything runs locally or in your CI. The scanner does not send your source anywhere.