Coding Agent Security Hooks: When Block Should Stop an Agent

A hook that checks each install before it runs is the right place to stop an agent, as long as only a complete finding ever stops it.
Coding agent security hooks check a package or a secret before the agent acts. When Block beats Notify, why a check must fail open, and how to install them.
October 28, 2026

A coding agent does not open a pull request after each decision. It runs a few hundred shell commands and file edits, then shows you a diff. If one of those commands installed a malicious package, its install scripts ran on the developer's machine long before anyone reviewed anything.

Coding agent security hooks move the check to the moment the agent acts. The agent calls the hook before each shell command and file edit. The hook checks the package or the credential, and the action either runs or is denied with a reason the agent can act on.

The hard question is not whether to check. It is when a check should stop the agent, and what should happen when the check itself cannot finish. This post covers both, with Heeler's Agent Hooks as the worked example.

Why the pull request is too late for an agent's install

Pull request guardrails are the right place to decide what merges. They are the wrong place to decide what installs. By the time a reviewer sees package.json, the package manager has already fetched the tarball and run its lifecycle scripts. npm runs preinstall and postinstall scripts as part of a normal install, and a malicious package uses exactly those hooks.

Agents make this worse in two ways. They install at a rate no reviewer can follow, and they install from memory. A model that has seen a package name in training will type it with confidence, whether or not that name exists on the registry, and whether or not the latest version is the one that was compromised last week.

A reviewer also sees the result, not the sequence. A diff shows the final manifest. It does not show that the agent installed four versions of a package on the way there, or that one of them carried a known vulnerability the agent later removed. The pull request check still matters, but it is the last gate, not the only one.

What a coding agent security hook checks

A hook is a small program the agent runs before it acts. The check sits inside the agent's own hook system, so the agent cannot skip it. That is the difference from a tool the agent calls on request: the MCP Server answers when the agent asks, a hook runs on every action, whether or not the agent asked.

Heeler's hook reads the command or edit on the machine and decides whether it adds a package. A command that adds no package, such as npm test or git status, gets no message. For an install, three cases matter:

  • Direct additions such as npm install lodash@4.17.21 or pip install requests==2.32.5. Several packages in one command, and installs chained with &&, are each checked.
  • Versionless additions such as npm install lodash. Heeler checks its recommended version and gives the agent the exact command to run instead.
  • Project installs such as npm ci or poetry install. Heeler checks each direct dependency added or changed in the manifest and lockfile since the last commit.

Manifest edits get the same treatment before the file changes. When the agent writes a dependency into package.json, pyproject.toml, pom.xml or go.mod, Heeler checks each direct dependency the edit adds or changes at an exact version. A rejected dependency leaves the file unchanged.

The check covers 15 package managers across JavaScript, Python, Rust, Go, .NET, Ruby and PHP. What leaves the machine is the package name, exact version, ecosystem, repository identity and base branch. The prompt, the full command line, file contents and secret values never leave the machine.

Notify or Block: which mode an agent hook should run in

Every Heeler hook runs in one of two modes. Notify is the default: the install runs, and Heeler reports what it found and what to use instead. Block is an install option: a rejected package is denied before the package manager runs, with the reason and the recommended version.

Start with Notify. It shows you what your agents install and what a Block hook would have denied, with no change to how developers work. Move to Block when you want rejected packages stopped before they install.

Block denies only a complete, positive finding:

  • an exact version Heeler rejects: known vulnerabilities, malicious intelligence, or a violation of your dependency policy;
  • a violation of a repository PR guardrail set to Block, evaluated with complete data;
  • a versionless install when Heeler checked its recommended version, so the agent can run the exact command instead.

Everything else goes ahead with a notice. A version range, a tag, a URL or a Git reference is not an exact version, so it is not denied. A command Heeler does not parse, such as an install inside a pipe or subshell, goes ahead with a notice that names the reason. A package that is not rejected gets no deny; that result covers the package version itself, not its transitive dependencies or install scripts, and the agent is told so.

The agent's deny text for a version with a known CVE:

Do not install lodash@4.17.20: Heeler dependency check rejected it (known_vulnerabilities): CVE-2021-23337; highest severity high. Heeler's recommended version is lodash@4.17.21; it will be checked again.

The agent retries with the recommended version, Heeler checks it again, and the install runs. Block is available on every supported agent.

A check that fails open is a design decision

Heeler's answer to a check that cannot finish is exact: a Heeler failure never blocks the agent. Only a complete, positive finding denies. If Heeler is unreachable, you are not signed in, the check times out, or heelercli fails, the action runs and the notice says it was not checked. Every hook fails open on any Heeler-side failure, including a crash of heelercli itself.

A hook sits in the path of every shell command every developer's agent runs. A fail-closed hook makes your security vendor's uptime, your laptop's network and your login token a dependency of git status. Developers respond to that in one way: they uninstall the hook. A check nobody runs blocks nothing.

Fail-open is only safe when the failure is visible and the cause is named. The notice tells the developer the action was not checked and why, for example auth_unavailable when heelercli is not signed in. heelercli hook <agent> doctor reports a missing or outdated Heeler entry and a heelercli path that cannot run. Before an unattended run, such as a container or a CI job, heelercli hook preflight confirms that the installed hooks can check anything, and fails the job when they cannot.

The same rule holds for the secret check, which scans for secrets when the agent commits or pushes. Only a credential that its provider confirms is live, that is not an exception in Heeler, and that this commit or push carries can deny. A credential the issuer does not confirm as live is never denied; the commit runs with a notice that names the path and rule. Package Block and secret Block are separate choices.

The agent's own credential needs a fixed boundary

A hook that calls Heeler needs a credential, and an agent that calls Heeler over MCP needs one too. The question is what that credential can do if the agent is talked into misusing it. Prompt injection through repository content and tool output is a listed risk in the OWASP Top 10 for LLM Applications, and so is excessive agency: an agent given more permission than its task needs.

Heeler's Agent API key is scoped for this. An agent key reads all of Heeler over REST and MCP within its owner's permissions, and acts only where it helps get code fixed: scans, guidance, remediation runs the owner created, secret re-checks, tickets and Slack messages. It cannot change rules, access or credentials. An agent holding one cannot turn a Block guardrail off, add an exception for the secret it just leaked, or create another key.

After creation, the Add API Key window shows the HEELER_API_KEY to set for hooks and CI, the HEELER_BASE_URL when your organization is not on app.heeler.com, and the MCP server URL. Set the key in the agent's environment, not in a file the agent can edit.

The last boundary is on the machine: a hook written with --use-path runs the first heelercli on the agent's PATH. If the agent can write to a directory on that PATH, it can put another program there and avoid the check. Install heelercli in a directory the agent cannot write to. Install and doctor warn when a directory on PATH is writable.

Installing coding agent security hooks on every machine

One policy only helps if it reaches every agent. Heeler's hooks cover 15 agents: Claude Code, Codex CLI, GitHub Copilot CLI, Cursor, Gemini CLI, Cline, Augment Auggie, Kiro, Factory Droid, JetBrains Junie CLI, Antigravity CLI, Devin, Amp, OpenCode and goose. Every agent runs the same package checks, policy and guardrails. Install takes a few commands per agent, from the install and manage page:

  1. Install the Heeler CLI and sign in: heelercli login
  2. Install the hook in Block mode: heelercli hook claude install --block
  3. Check the installation: heelercli hook claude doctor
  4. Restart the agent so it loads the hook.

Replace claude with the hook name of your agent. Add --secrets-check to scan commits and pushes, and --secrets-block to deny a confirmed-live credential. Running install again with different options replaces the Heeler entries and keeps every other hook and setting.

Hooks run on Linux, macOS and Windows for all 15 agents, with the same checks, modes and messages on each. On Windows, each hook starts Windows PowerShell 5.1 by its full path and passes its code as an encoded command, so it does not depend on your execution policy and needs no Git Bash or WSL (goose excepted).

Two install details catch teams out. Project-scope hook files name the heelercli path of the machine that wrote them, so keep them out of version control unless you installed with --use-path and every machine has heelercli on the agent's PATH. And Codex runs only hooks you trust: after install, run heelercli hook codex trust or trust the entries in /hooks.

Hooks, guardrails and skills: one policy at three moments

Hooks are one of three places a coding agent meets your policy. At session start, the hook gives the agent Heeler's security guidance and the repository's PR guardrails, so the agent knows the minimum publish age rule before it types an install command. When the application is assessed against a standard such as OWASP ASVS, the guidance also lists the requirements that apply, Block-enforced ones first.

During the work, the agent can ask. The MCP pre-add dependency check evaluates the repository's pull request guardrails for the exact version being added, so a package that would fail a minimum-age or CVSS rule at pull request time is flagged before it is installed. Agent Skills run inside the agent to check a package before adding it and scan for secrets before a commit; we covered them in Centralized Security for Agentic Coding. Then the hook checks the action whether or not the agent asked.

At pull request time, the same guardrails run again on what was committed. Hook checks send the repository and manifest path, so a minimum publish age guardrail is enforced when the package is installed, and a deny names the CVEs, severity, fixes and the configured threshold. The policy is defined once and applied at install, in the conversation and at merge.

What to do

  1. Install hooks in Notify on every machine where an agent runs, and read the notices before you change anything.
  2. Turn on Block for package installs once the notices show what it would have denied. Where the deny rate would be high, tune the underlying guardrails first.
  3. Add --secrets-check, then --secrets-block. The block fires only on a confirmed-live credential that is not an exception, so the cost to developers is low.
  4. Issue Agent API keys for hooks, CI and MCP. Do not give an agent a full-access key.
  5. Run heelercli hook preflight as a CI step before any unattended agent run.
  6. Put heelercli in a directory the agent cannot write to, and keep project hook files out of version control.
  7. Set the repository guardrails you want enforced at install time, such as minimum publish age, and let the hook apply them.

FAQ

What are coding agent security hooks?

Coding agent security hooks are checks that run inside an AI coding agent's hook system before each shell command or file edit, so a package install or manifest change is checked before it happens. Unlike a tool the agent calls on request, a hook runs on every action and the agent cannot skip it.

When should a hook block an agent instead of notifying?

Block when the check has a complete, positive finding: a known vulnerability, malicious intelligence, a dependency policy violation, or a Block guardrail evaluated with complete data. Start in Notify to see what Block would deny, then switch.

What happens if the security check fails or times out?

The action runs, with a notice that it was not checked and why. Heeler's hooks fail open on every Heeler-side failure, including a crash of heelercli itself, so only a positive, complete finding ever stops the agent.

Does a hook send the agent's prompt or my code to Heeler?

No. A package check sends the package name, exact version, ecosystem, repository identity and base branch. The prompt, the full command line, file contents and secret values never leave the machine.

Do agent hooks work on Windows?

Yes. Hooks install and run natively on Windows for all 15 supported agents, using Windows PowerShell 5.1 with no Git Bash or WSL needed, except goose, which needs Git Bash on the PATH.

If your developers run coding agents, the install command is already the enforcement point, whether or not anything checks it. Heeler's Agent Hooks put one policy there for 15 agents on three operating systems, deny only on a complete finding, and never stop an agent because Heeler could not answer. Get a demo

What’s new on Heeler
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Related resources

See All Resources