AGENTS.md is not a security control

AGENTS.md and CLAUDE.md can't enforce security rules, because the model weighs them as context and injected text, a misread rule, or an edited file can defeat them. A hook policy is enforced outside the model by the agent's own process. Arcjet hook policies are the enforced counterpart to an instruction file: one policy for Claude Code, Copilot, Cursor, and Codex, decided before the tool runs, while instruction files remain the right place for conventions.

10 min read
In short: AGENTS.md and CLAUDE.md can't enforce security rules, because the model weighs them as context and injected text, a misread rule, or an edited file can defeat them. A hook policy is enforced outside the model by the agent's own process. Arcjet hook policies are the enforced counterpart to an instruction file: one policy for Claude Code, Copilot, Cursor, and Codex, decided before the tool runs, while instruction files remain the right place for conventions.

Can AGENTS.md or CLAUDE.md enforce security rules?

No. AGENTS.md, CLAUDE.md, and similar instruction files are text that a coding agent loads into the model's context, so a rule in them is advice that the model can misapply, forget, or be talked out of by injected text. To enforce a rule, deny the action in a hook that runs outside the model, before the tool call happens.

An agent loads an instruction file at the start of a session or when it enters a directory. The file describes how a repository works: the build and test commands, the code style, which directories are generated, and what the team expects a change to look like. A good instruction file makes the agent more useful and saves every developer from repeating the same corrections.

Teams also write rules into these files, such as "never run rm -rf", "don't read .env", or "only use the approved MCP servers", where MCP (Model Context Protocol) servers are external tool servers that the agent connects to. Those lines read like a policy, but nothing enforces them like one.

Arcjet coding agent hooks are the enforced counterpart to those lines. You write the rule once as an Arcjet policy, and Arcjet decides each tool call against it before the tool runs, on Claude Code, GitHub Copilot, Cursor, and OpenAI Codex. The instruction file keeps telling the agent what you want, and Arcjet denies the call when the agent does something else.

Why aren't instruction files a security control?

An instruction file is input to the model. The model reads it alongside the developer's prompt, the files that it opened, the output of the commands that it ran, and the web pages and MCP responses that it fetched. The model then decides what to do next, and nothing outside the model checks that the decision followed the file.

That design has the following consequences:

  • Injected text sits in the same context. A README, an issue comment, a web page, or an MCP response can contain instructions of its own. The model has no reliable way to tell the team's rules from text that an attacker wrote to look like rules, and a sentence such as "ignore previous instructions" competes directly with your file.
  • The model can misapply a rule. A rule that says "don't delete production data" depends on the model recognizing that a command touches production data. A model that is trying to fix a failing migration might decide that a reset is the fix.
  • Context changes during a session. Long sessions compact their context, which discards earlier material. Arcjet records Claude Code's PreCompact event, which marks context discarded mid-session.
  • The agent can edit the file. An instruction file is a file in the repository. An agent with write access, or a developer, can change it, and the next session follows the new text.

A rule that holds only when the model follows it is guidance. A security control has to hold when the model is wrong, confused, or manipulated.

What enforces a rule outside the model?

The agent's own process enforces it – the client program that runs the model's tool calls, sometimes called the harness. Claude Code, GitHub Copilot, Cursor, and OpenAI Codex each fire hooks at fixed points in the session, including before a tool call and before a prompt reaches the model. A hook sends the pending action to a policy, and the agent's process applies the answer. If the policy denies a tool call, the tool doesn't run, whatever the model intended.

With Arcjet coding agent hooks, the hook posts the event to Arcjet. Arcjet runs every policy attached to that event at the edge, in over 300 data centers, and returns a denial in the vendor's own response shape, or {} to allow. The model sees only the rule ID, for example Blocked by Arcjet policy: destructive-command., so the answer contains nothing for the model to negotiate with. Policies are written in Rego and cover all four agents with one set of inputs, so you don't maintain per-vendor rules, and no code changes are needed. For examples, see block dangerous commands, stop coding agents reading secrets, and restrict MCP servers.

The following table compares the two:

Instruction fileArcjet hook policy
Who reads itThe modelThe agent's own process and the policy service
When it appliesWhen the model weighs it against the rest of its contextOn every event that the hook is installed for
Effect of injected textCan override or contradict it

None on the decision, which reads the tool call, not the conversation

Who can change itAnyone who can edit the repository, including the agent

Whoever publishes the policy, when hooks come from managed settings

Record of what happenedNoneEvery session and decision in the Arcjet Console

The same reasoning applies to other controls that depend on the model or on a person. For more information, see canUseTool is not a policy gate and human approval is not a security policy.

What are instruction files still good for?

Instruction files are the right place for conventions, context, and preferences, and a good one reduces how often a policy has to deny anything. Use them for the following purposes:

  • Describe the build, test, and lint commands, so that the agent doesn't guess.
  • Explain the repository's structure and which files are generated.
  • State the team's preferences, such as avoiding force pushes, so that the agent chooses the allowed path first.
  • Explain what a denial means. If your policies use rule IDs such as credential-path or unlisted-mcp-server, a line that says how to request an exception helps the agent and the developer respond to a denial.

When a rule matters, write it in both places. The instruction file tells the agent what you want, and the hook policy enforces it when the agent does something else.

Can you see which instructions an agent loaded?

You can on Claude Code. Claude Code fires an InstructionsLoaded event when a CLAUDE.md enters context, and Arcjet records it as part of the session's activity in the Arcjet Console. When you review a session, you see what the agent was told next to what it tried to do and which calls Arcjet denied. The event is a record for review rather than an enforcement point, so the file loads either way.

Arcjet also records Claude Code's ConfigChange event, which fires when settings change and is a tamper signal. You can export decisions to Datadog, Splunk, SentinelOne, Panther, and Amazon S3 (Enterprise plan) for detection and alerting.

How do you keep the hook from being removed?

A hook works as a control only if developers and agents can't turn it off. Arcjet hooks install through the vendor's managed channel rather than a repository file, so developers can't remove them without administrator access. Use the vendor's lockdown setting as well. Managed settings are configuration that an administrator deploys to developer machines, often through mobile device management (MDM), and that a developer can't override. Each agent has its own lockdown setting:

  • Claude Code. Use endpoint-managed or server-managed settings and set allowManagedHooksOnly, so that a developer's own hooks don't replace yours. Only a local administrator can remove a managed settings file on a device, which matters if every developer is one. Server-managed settings can be removed only by switching provider, but exporting a CLAUDE_CODE_USE_* provider variable skips the server-managed fetch. Use endpoint-managed settings for configuration that must always apply.
  • OpenAI Codex. Set allow_managed_hooks_only in requirements.toml and pin [features].hooks = true.
  • GitHub Copilot CLI. Put the hook file in /etc/github-copilot/policy.d/, root-owned and not group- or world-writable.
  • Cursor. Use enterprise MDM or Team dashboard hooks, which outrank a developer's project or user file.

Claude Code and Copilot fail open on an HTTP hook: on a timeout or network error, these vendors let the tool call go ahead unchecked. Arcjet evaluates at the edge to keep the added latency small, and the Codex and Cursor command wrapper fails closed. For more information, see coding agent hooks fail open. To find sessions that ran without hook decisions, pair the hooks with OpenTelemetry and Claude Compliance API activity, which Arcjet records for visibility into sessions that the hooks don't reach. For more information, see observe agent activity.

How does Arcjet enforce the rules in your instruction files?

With Arcjet, the rules in your AGENTS.md or CLAUDE.md that must hold become policies that the agent's own process enforces before the tool runs, regardless of what the model read. The following capabilities apply:

  • One policy for Claude Code, Copilot, Cursor, and Codex, decided from the hooks that the agents already fire.
  • Hooks installed through managed settings, so developers can't remove them without administrator access.
  • Starter policies in the Arcjet Console for destructive commands, credential reads, and unapproved MCP servers, with dry run so you see what a rule would deny before it goes live.
  • A record of every session and decision, which an instruction file can't give you.

The same policy engine protects custom agents that you build, so coding agents and custom agents share one approach.

To start, pick the rules in your instruction file that the model must not ignore, and publish the matching starter policies in dry run, a mode in which Arcjet records what a rule would have denied without denying it. Keep the instruction file for everything else. For per-agent setup, see coding agent security.

Frequently asked questions

Can a coding agent ignore rules in AGENTS.md or CLAUDE.md?

Yes. The model reads the file as context alongside everything else in the session, including text from READMEs, web pages, and MCP responses. Nothing outside the model checks that its next action followed the file.

What should I use instead of CLAUDE.md to block dangerous actions?

Use a hook policy. Claude Code, GitHub Copilot, Cursor, and OpenAI Codex fire hooks before tool calls, and the agent's own process refuses a call that the policy denies, whatever the model intended. With Arcjet, one policy covers all four agents, and you install the hooks through managed settings so developers can't remove them without administrator access.

Should I stop writing AGENTS.md files?

No. Use AGENTS.md files for build commands, conventions, and preferences, and to explain what a policy denial means. Enforce the rules that matter with a hook policy as well.

Can I see which CLAUDE.md files a session loaded?

Yes, on Claude Code. Arcjet records Claude Code's InstructionsLoaded event when a CLAUDE.md file enters context. It's a record for review, not an enforcement point.

AI runtime security in your code

Protect your AI agent workflows with Arcjet

Install Arcjet hooks for Claude Code, Copilot, Cursor, or Codex so your rules are enforced outside the model.