Protect Agent Config
Refuses a matched shell command before it runs. Blocks on an agent's file writes and at turn end.
Acts on
Shell command · File write · Turn end
When
Before the command runs · before the file write · at turn end
Tested
1593 of 1593 pass
In a git repo
In agent
What it does
Stops an agent editing its guardrails (MITRE ATLAS AML.T0081). Shell guard refuses writes to AGENTS.md, whole agent folders (.claude/, .cursor/, .codex/, .gemini/, .agents/, .chock/, ...), MCP/hook client configs (.mcp.json, ...), guardrails toggles, plugin install markers, chock.lock, hook files of Cline, Kiro, Augment, Windsurf and Devin (user and machine level), ~/.claude.json, Claude Code plugin roots, project config of Kilo Code, opencode, Factory, Amp, Continue and Goose, .git/{hooks,config}, policy implementations/: redirect, rm/mv/tee/sed -i, cp into, git checkout/restore, a write through a symlink; CLAUDE_CODE_PLUGIN_DIRS, claude --plugin-dir, chock resume (best effort). Any case. An instruction file under docs/ asks a person. Coarse: also eval or sh -c of computed text, shells fed by pipe/variable, interpreter one-liners naming such a path. Reads, chock sync pass. Edit/Write: tool gate, same set and verdicts. Misses: user config under ~/.config/, writes a script makes, an existing hard link.
Chock adds friction. It is not a security boundary.
Its label on each agent
The catalog grades each policy on each agent. Pick an agent to build with this policy:
- Claude Code TestedBlocks Refuses a matched shell command before it runs. Blocks on an agent's file writes and at turn endBuild →
- Cursor TestedBlocks Refuses a matched shell command before it runs. Where its description says it asks, it asks. Blocks on an agent's file writes and at turn end. Where its description says it asks, it refuses at both points, because this client cannot prompt at either pointBuild →
- Codex TestedBlocks Refuses a matched shell command before it runs. Where its description says it asks, it refuses, because this client cannot prompt before a shell command. Blocks on an agent's file writes and at turn end. Where its description says it asks, it refuses at both points, because this client cannot prompt at either point. If the hook errors, the action goes through (not witnessed; the vendor's row is only partly live-run)Build →
- GitHub Copilot TestedBlocks Refuses a matched shell command before it runs. Where its description says it asks, it asks in VS Code and refuses in Copilot CLI, because it cannot prompt there. Blocks at turn end only. It does not check a file write when it happens. Where its description says it asks, it refuses at turn end, because this client cannot prompt there. If the hook errors, the action goes through (not witnessed; the vendor's row is only partly live-run)Build →
- Devin TestedBlocks Refuses a matched shell command before it runs. Where its description says it asks, it refuses, because this client cannot prompt before a shell command. Blocks at turn end only. It does not check a file write when it happens. Where its description says it asks, it refuses at turn end, because this client cannot prompt there. If the hook errors, the action goes through (vendor docs only, not witnessed)Build →
- Grok Tested Not graded yet for GrokBuild →
- goose Tested Not graded yet for gooseBuild →
- Antigravity Tested Not graded yet for AntigravityBuild →
- OpenHands Untested Not graded yet for OpenHandsBuild →
- Kimi Code Untested Not graded yet for Kimi CodeBuild →
- Factory Droid Untested Not graded yet for Factory DroidBuild →
See it in action
Refused
An agent rewrites its own permission file in place.
sed -i s/deny/allow/ .claude/settings.json
Allowed
An agent reads its permission file.
cat .claude/settings.json
Both examples are this policy's own test cases.
What it misses
User config under ~/.config/, writes a script makes, an existing hard link.
Latest change
0.7.6 · · Behaviour change (SR-2d2e, Claude Security finding F24; eval cases tc-1588 to tc-1593; tests in test_protect_agent_config_sr2e.py). mkdir, mkdir -p, md, and each spelling the guard already reads for other verbs (braces, variables, cd then a relative path, bash -c, quoting, \\ separators, capitals), is refused when it makes a folder at or under .chock/compiled, the one protected path whose bare existence a gate reads (the constant PRESENCE in pathset.py, checked against the protected paths in a test; dockerfile-compose-security reads .chock/compiled/<id> as an installed sibling). An empty folder planted there misled it. A mkdir anywhere else stays open: build/out, .claude/commands, .cursor, .agents/policies/<id> (no gate reads a bare folder there; writes inside are still refused).