How do you secure AI coding agents like Claude Code, Copilot, Cursor, and Codex?

To secure AI coding agents, check each tool call and prompt against a policy before the agent acts, and install that check through managed configuration that developers can't remove. Arcjet runs one policy across Claude Code, GitHub Copilot, Cursor, and OpenAI Codex through the hooks each agent fires, while OpenTelemetry and the Claude Compliance API add visibility without blocking.

20 min read
In short: To secure AI coding agents, check each tool call and prompt against a policy before the agent acts, and install that check through managed configuration that developers can't remove. Arcjet runs one policy across Claude Code, GitHub Copilot, Cursor, and OpenAI Codex through the hooks each agent fires, while OpenTelemetry and the Claude Compliance API add visibility without blocking.

What does it take to secure an AI coding agent?

To secure an AI coding agent, check each action against a policy before the agent takes it, and install that check where developers can't remove it. Claude Code, GitHub Copilot, Cursor, and OpenAI Codex all support hooks: configuration entries that send a pending tool call or prompt to an outside service and wait for its answer. Deploy the hooks through each vendor's managed configuration, then record every session so you can find the ones the hooks missed. Instructions in AGENTS.md or CLAUDE.md don't do this job, because the model reads them as context and can ignore them.

A coding agent doesn't only suggest code. It runs shell commands, reads and writes files, fetches URLs, and calls Model Context Protocol (MCP) servers, which connect the agent to outside tools and data. It does all of that with the developer's credentials: their SSH keys, cloud tokens, .env files, and access to every repository they can push to.

An agent that acts can delete a directory, push over shared history, read ~/.aws/credentials, pipe a download into a shell, or send source code to a host nobody reviewed. Some of those actions come from the developer's request. Others come from instructions the agent read in a README, an issue comment, a web page, or an MCP response, which is how prompt injection reaches a coding agent.

Security and platform teams usually ask for the following three things:

  • Visibility: which agents run in the organization, who runs them, and what they do.
  • Guardrails: a way to refuse specific actions before they happen, such as destructive commands, credential reads, unapproved MCP servers, or disallowed models.
  • Governance: one policy that applies whichever agent a developer chose, deployed through the channels IT already uses for other managed software.

Arcjet meets all three with one policy across Claude Code, GitHub Copilot, Cursor, and OpenAI Codex. It answers the hooks those agents already fire, so it decides each tool call and prompt before the agent acts, with no SDK and no code change. You install it through managed settings or MDM, so developers can't remove it without administrator access. Every session and decision appears in the Arcjet Console, and OpenTelemetry and the Claude Compliance API show the sessions the hooks don't reach.

For why instruction files can't meet any of these needs, see AGENTS.md is not a security control. If you already know which agent you're securing, go to the guide for Claude Code, GitHub Copilot, Cursor, or OpenAI Codex. The rest of this article explains the model that those guides share.

How can you see and control what a coding agent does?

There are three paths, and only hooks can refuse an action.

PathWhat it doesCan it block an action?What it covers
Hooks

The agent calls a policy service at each lifecycle event, such as before a tool call or before a prompt reaches the model.

Yes, on the events that ask before they act.

Claude Code, GitHub Copilot, OpenAI Codex, and Cursor, wherever the hook configuration reaches.

OpenTelemetry

A client you already run exports its own logs and traces over the OpenTelemetry protocol (OTLP).

No. It records what happened.

Clients configured to export, such as Claude Code through managed settings.

Claude Compliance API

A service polls Anthropic for your organization's activity and, with a Compliance Access Key, session transcripts.

No. It records what happened.

Sessions in your Anthropic organization, including clients you never configured.

Arcjet supports all three and shows them in the same Arcjet Console views. Use the observe-only paths for discovery before you enforce anything, and as a backstop afterward. A session that appears in OpenTelemetry or Claude Compliance API activity with no hook decision beside it is one your hooks didn't reach. Arcjet also exports decisions to Datadog, Splunk, SentinelOne, Panther, and Amazon S3 (Enterprise plan), so your security team can build detection and alerting on them.

Send the backstop to a separate Arcjet site from the hooks. If more than one path feeds the same site, each session is ingested twice under different identifiers. For more information about setting up the observe-only paths, see Observe agent activity.

Is a coding agent hook a gateway, a proxy, or a browser extension?

It's none of those. A hook is a configuration entry that the agent's own process runs at a named point in its lifecycle. That process is the Claude Code CLI or IDE extension, the Copilot CLI, the Codex CLI or app, the Cursor editor, or the cloud environment that each vendor runs for its hosted agent. When the agent is about to run rm -rf build, it pauses, sends the pending tool call to the hook, and waits for an answer.

This design has the following consequences for how you deploy and evaluate it:

  • It decides the action, not the model call. Model traffic between the agent and Anthropic, OpenAI, GitHub, or Cursor goes where it always went. Arcjet sees the action the model asked for, which is the point where a policy can refuse it.
  • There is no TLS interception and no local agent process to install. Claude Code and Copilot send an HTTP request directly. Codex and Cursor run hooks as commands, so the install adds a small shell script that posts the hook payload to Arcjet with curl and prints the answer.
  • There is no SDK and no code change. The developer keeps working the same way. You publish policies in the Arcjet Console, and a change takes effect in real time without redeploying the hook file.
  • It runs where the agent runs. On a laptop, the hook fires on the laptop. In a cloud agent, it fires in the vendor's cloud environment, which needs network access to decide.arcjet.com.

Because the hook lives in the agent's configuration, who can remove it depends on where that configuration file lives and who can edit it. For the answer per vendor, see How do you roll out hooks across an organization?.

Can one policy cover Claude Code, Copilot, Cursor, and Codex?

Yes. Each vendor names its events and tools differently: Claude Code calls its shell tool Bash, Cursor calls it Shell, and Codex reports exec_command. Arcjet translates each payload into one fixed set of inputs. A policy reads tool_kind, command, command_tokens, paths, domains, mcp_server, prompt, and model without caring which agent sent them, so you write a policy once and it applies to every supported agent. You don't maintain per-vendor rules.

You write policies in Rego, the Open Policy Agent policy language, for fine-grained control over each rule. Write Rego directly or use the visual builder in the Arcjet Console. This starter policy from the coding agent policies documentation denies destructive shell commands on any of the four agents:

destructive := {"rm", "rmdir", "shred", "dd", "mkfs", "sudo", "doas", "trash"}
deny contains "destructive-command" if {
input.values.tool_kind == "shell"
some token in input.values.command_tokens
lower(token) in destructive
}

Compare tool_kind, not tool_name. A tool name that isn't in Arcjet's mapping table becomes tool_kind: other, which a rule over the kind never matches.

The Arcjet Console offers starter policies for the common cases, each covering a single concern. The following guides explain each one:

Arcjet runs every policy attached to an event in one round trip and applies the most restrictive decision, so you can keep policies small and publish several.

When does a coding agent policy run?

In the Arcjet Console, you attach each policy to one or more Execute on options: Tool call, Prompt, and Model switch.

Execute onRuns beforeInputs the policy can read
Tool call

The agent runs a command, reads or writes a file, calls an MCP server, or fetches a URL.

tool_name, tool_kind, command, command_tokens, paths, domains, destinations, mcp_server, mcp_tool, model

Prompt

Text reaches the model: what the developer typed, and what a slash command expanded into.

prompt, model
Model switch

Claude Code changes which model the session uses. A denial keeps the current model.

model

Policies run only on events where the agent asks before it acts. Arcjet records every other lifecycle event, such as post-tool-use, stop, session-start, or config-change, as activity without deciding it, because the action has already happened.

What can each coding agent enforce?

You write the policy once, and each vendor decides which hook answers it honors. Arcjet enforces tool-call policies on all four agents. The following table summarizes the per-vendor differences from the Arcjet coding agents documentation.

AgentHook typeTool callPromptModel allowlistIf the hook can't reach Arcjet
Claude CodeHTTPEnforced on PreToolUse and PermissionRequest.Enforced on UserPromptSubmit and UserPromptExpansion.

Denies the switch on PreModelSwitch. Prompt and tool events carry no model.

Fails open, except PreModelSwitch, where a timeout blocks the switch.

GitHub CopilotHTTP (CLI and cloud agent)Enforced on preToolUse and permissionRequest.

Recorded, not enforced. Copilot drops hook output on userPromptSubmitted.

Not covered. Copilot payloads have no model field.Fails open.
OpenAI CodexCommand wrapper

Enforced on PreToolUse and PermissionRequest. Hosted tools such as WebSearch skip PreToolUse.

Enforced on UserPromptSubmit.

Denies the prompt and the tool call while a disallowed model is selected. No switch hook.

Fails closed. The wrapper exits 2.
CursorCommand wrapperEnforced on preToolUse. Cursor has no permission-request hook.

Enforced on beforeSubmitPrompt in the IDE. Cloud agents don't run it.

Denies the prompt and the tool call while a disallowed model is selected. No switch hook.

Fails closed with failClosed: true.

A denial uses the vendor's own response shape and names the rule ID, for example Blocked by Arcjet policy: destructive-command. An allow is always an empty object, {}. Arcjet never answers with an explicit allow, such as permissionDecision: "allow" or Cursor's permission: "allow". The agents treat an explicit allow as a grant that skips their own permission flow, so an Arcjet answer can take a permission away but never grants one.

GitHub Copilot agent hooks in VS Code are in preview and don't support the HTTP hook type, so the Arcjet hook file applies to the Copilot CLI and the cloud coding agent. For each install in detail, see the guides for Claude Code, GitHub Copilot, Cursor, and OpenAI Codex.

How do you roll out hooks across an organization?

Each vendor offers managed configuration: settings that an administrator deploys and that take precedence over anything a developer writes. You deploy it with the mobile device management (MDM) or configuration management tooling you already use, or through the vendor's admin console.

AgentManaged channelWho can remove it
Claude Code

A managed settings file such as /Library/Application Support/ClaudeCode/managed-settings.json on macOS, MDM managed preferences, or server-managed settings in the claude.ai admin console.

A local administrator for the device file. Claude Code skips server-managed settings when a session uses a third-party model provider or sets ANTHROPIC_BASE_URL to somewhere other than the Anthropic API.

GitHub Copilot

A root-owned /etc/github-copilot/policy.d/arcjet.json for the CLI, and .github/hooks/*.json on the default branch for the cloud agent.

Users can't disable a CLI policy hook. Anyone who can merge to the default branch can change a repository file.

OpenAI Codex

A system requirements.toml, MDM managed preferences, or cloud-managed requirements for ChatGPT Business and Enterprise.

A local administrator for the device file.
Cursor

An enterprise hooks.json deployed by MDM, or Team hooks in the Cursor dashboard on the Enterprise plan.

A local administrator for the device file, or an administrator in the dashboard.

Managed configuration puts the Arcjet hooks outside a developer's reach, so a developer without administrator access can't remove them. Where your developers have local administrator rights, pair the device file with a server-side channel where the vendor offers one, as described in Which gaps do hooks leave, and how do you cover them?.

Lock the configuration so a developer's own hooks and settings can't run beside yours. Claude Code uses allowManagedHooksOnly and disableBypassPermissionsMode. Codex uses allow_managed_hooks_only in requirements.toml. A committed repository hook file needs no device management, but any developer who can edit the repository can remove it, so treat it as a pilot rather than a control.

How fast is a hook decision, and what happens if the service is down?

Arcjet evaluates policies at the edge in over 300 data centers, so the added latency stays small. The agents run matching hooks for an event in parallel, so the Arcjet entries add one request of latency, typically a few tens of milliseconds. The install templates set a 5-second timeout on each entry, except Claude Code's PreModelSwitch, which uses 30 seconds.

Each vendor decides what happens on a timeout or error. Claude Code and Copilot built their HTTP hooks to fail open: they let the action through when the hook gets no answer. On those agents, the service's availability and latency set how strong enforcement is, which is why Arcjet answers from the edge. For Codex and Cursor, the Arcjet wrapper fails closed: it denies instead, so the control stays in force through an outage, and a wrong key denies every prompt and tool call. For the full breakdown, see Do coding agent hooks fail open?.

What happens when a developer hits a false positive?

Arcjet starts every new rule in dry run, which records what the rule would have denied without denying anything. Publish the policy, let developers work, and review the tool calls each dry-run rule would have denied in the site's Activity in the Arcjet Console. When the results look right, set the rule live.

When a live rule denies a call, the agent receives the rule ID, so the developer and the security team both see which rule fired. Choose rule IDs that a developer can understand. To fix a false positive, edit the policy in the Arcjet Console. The change takes effect in real time, with nothing to redeploy to laptops.

Which gaps do hooks leave, and how do you cover them?

Hooks are the only path that refuses an action, and each vendor sets what its hooks can reach. The following list names each gap and what to pair Arcjet with:

  • Claude Code and Copilot fail open. The vendors built their HTTP hooks to let a call through on a timeout, a network error, or a non-2xx response, except Claude Code's PreModelSwitch. Arcjet answers from the edge to keep decisions inside the timeout, and OpenTelemetry or Claude Compliance API activity shows any session that ran without one.
  • Copilot drops the output of a prompt hook. Arcjet records the prompt decision and marks it as not enforced. Tool-call policies enforce on Copilot as on every other agent.
  • Codex hosted tools skip PreToolUse. WebSearch and other hosted tools don't use Codex's local hook path, so a tool-call policy doesn't see them. Arcjet decides every tool call on Codex's local hook path.
  • No agent lets a hook withhold a tool result. The tool has already run by the time a recorded event fires, so a poisoned web page or MCP response, the most common route for an injection into a coding agent, reaches the model. Arcjet tool-call policies stop what the agent tries to do next, and prompt policies screen what the developer sends.
  • A local administrator can edit a device-level managed file. Pair the device file with a server-side channel where the vendor offers one, such as Claude Code server-managed settings or Cursor Team hooks, and compare hook decisions against OpenTelemetry or Claude Compliance API activity.
  • A hook applies to a client, not a person. A developer can delete a repository-level hook, and a third-party model provider skips Claude Code's server-managed settings fetch. A developer calling a model API from another tool is outside every client's hooks. Use managed configuration rather than repository files, and reconcile against an observe-only backstop.
  • Personal accounts use the same product domains as the enterprise tier. Neither hooks nor the Claude Compliance API see a personal Claude, ChatGPT, Copilot, or Cursor login on a corporate laptop. Pair Arcjet with network or device controls that refuse personal accounts. For more information, see how to block personal AI accounts on work laptops.

Where does Arcjet fit in coding agent security?

With Arcjet, one policy decides every tool call and prompt across Claude Code, GitHub Copilot, Cursor, and OpenAI Codex before the agent acts, and you see every session in one place. Arcjet gives you the following capabilities:

  • One policy for four agents: Arcjet translates each vendor's hook payload into the same inputs, so a Rego policy written once applies everywhere.
  • Enforcement developers can't remove: you install the hooks through managed settings or MDM, and change policies in the Arcjet Console in real time without touching a device.
  • Low added latency: Arcjet evaluates policies at the edge in over 300 data centers.
  • Visibility and export: hook decisions, OpenTelemetry, and Claude Compliance API activity appear in the same Arcjet Console views, and decisions export to Datadog, Splunk, SentinelOne, Panther, and Amazon S3.

The same policy engine protects custom agents that you build with frameworks such as LangChain, the OpenAI Agents SDK, or the Vercel AI SDK, so coding agents and custom agents share one approach.

The following guides cover each part of a rollout:

To start, install the hooks for one agent from its guide, then publish the coding-agent.destructive-command starter policy in dry run and review what it would deny in Activity before you set it live.

Frequently asked questions

How do you secure AI coding agents?

Check each tool call and prompt against a policy before the agent acts, using the hooks that Claude Code, GitHub Copilot, Cursor, and OpenAI Codex fire. Deploy the hooks through each vendor's managed configuration so developers can't remove them, and record sessions through OpenTelemetry or the Claude Compliance API to find the ones the hooks missed. Arcjet does this with one policy across all four agents, decided at the edge before the tool call runs, with every session and decision recorded in the Arcjet Console.

Is coding agent security a gateway or proxy in front of the model?

No. A coding agent hook is a configuration entry that the agent's own process runs at a lifecycle event, such as before a tool call. It runs on the laptop or in the vendor's cloud agent and sends the pending action to a policy service. Model traffic isn't intercepted.

Can one policy cover Claude Code, GitHub Copilot, Cursor, and OpenAI Codex?

Yes. Arcjet translates each vendor's hook payload into one set of inputs, so a policy that reads tool_kind, command, paths, domains, or mcp_server applies to all four agents. Each vendor still decides which denials it honors. For example, GitHub Copilot drops prompt denials.

Do I need MDM to deploy coding agent hooks?

Not to start. A committed repository hook file works for a pilot, but a developer can remove it. For an organization-wide control, deploy the vendor's managed configuration through mobile device management (MDM), configuration management, or the vendor's admin console, such as Claude Code server-managed settings or Cursor Team hooks.

Can a local admin bypass coding agent hooks?

Yes. A local administrator can edit or delete a device-level managed file. Pair device files with a server-side channel where the vendor offers one, and compare hook decisions against OpenTelemetry or Claude Compliance API activity to find sessions that ran without them.

Do coding agent hooks see personal AI accounts?

No. A personal Claude, ChatGPT, Copilot, or Cursor login uses the same product domains as the enterprise tier, and neither hooks nor the Claude Compliance API see it. Refuse personal accounts with tenant restrictions at the network or device.

AI runtime security in your code

Protect your AI agent workflows with Arcjet

Install Arcjet hooks for Claude Code, GitHub Copilot, Cursor, or OpenAI Codex and publish your first policy in dry run.