Repository navigation
Orchestrator-owned guardrails: protected config, spawn-time hook packs, injection and secret scanning - #423
Merged
currentbits merged 9 commits intoAug 17, 2026
Conversation
Pure, dependency-free policy shared by every enforcement point: tool-call classification (protected config, credential reads, shell tiers, writes outside the worktree), inbound injection scanning, outbound secret scanning. CODER_GUARDRAILS=off disables; every path fails open. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deny answers the CLI immediately (no pending prompt, no awaitingInput)
and writes a transcript event. Ask still prompts, with {rule,reason}
attached for the UI. classifyTool throws fail open to today's prompt.
Reject agent-written (source mcp) memory entries that match prompt-injection patterns. Prefix poisoned GitHub issue bodies with an untrusted-content banner so the agent still sees the issue, as data.
Block gh pr create, git push, and generated/used commit messages when scanSecrets finds credentials. Hits throw on the existing Error channels with redacted excerpts. Scanner and diff failures log and fail open.
The ask tier only helps if the user sees why the call was flagged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…into coder/orchestrator-owned-guardrails-protected--a32742
The MCP tools now set source themselves: an agent that could label its own write 'app' walked straight past the scan, which is keyed on source 'mcp'. Scan supersede too — rewriting a live entry poisons the same channel as writing a new one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…into coder/orchestrator-owned-guardrails-protected--a32742
Share one assertNoOutboundSecrets instead of a second copy in commitmsg. Diff from the fork point on a first push: HEAD~1..HEAD covered one commit of however many the branch carried, which reads as coverage it did not have. Log the 2 MB truncation for the same reason. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
currentbits
deleted the
coder/orchestrator-owned-guardrails-protected--a32742
branch
October 3, 2026 16:07
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #409.
The agent cannot police itself: a prompt injection that lands in its context can rewrite the very hooks meant to stop it. Solenta is the one layer that sits outside the agent, so policy lives there.
electron/guardrails.jsis a pure, dependency-free module with three functions. Every enforcement point shares it, so there is one policy rather than one per call site.Protected config and the spawn-time hook pack
classifyTool()runs at the Claudecan_use_toolseam inrunner.js. Adenyis answered immediately and never reaches the user — the whole point is that an injected agent doesn't get to social-engineer a yes. Anaskfalls through to the normal permission prompt with the reason shown, so the user isn't approving blind..claude/hooks,.claude/settings*.json,.claude/agents,.mcp.json,.github/workflows,.git/hooks,.git/config,coder-store.json.env,*.pem/*.key,.ssh,.aws,.npmrcand private keys (.env.exampleand friends still pass)rm -rfoutside the worktreeInbound injection scanning
scanInjection()covers override phrases, fake system tags, concealment, exfil and credential-harvest imperatives, zero-width and bidi characters, and hidden HTML comments.The memory server is a cross-agent propagation channel — poison one entry and every future thread that loads it is compromised — so poisoned
memory_storeandmemory_supersedewrites are rejected with the matched rule named. The MCP tools now setsourcethemselves; previously an agent could label its own writeappand walk straight past a check keyed onsource === 'mcp'.Issue bodies are banner-prefixed rather than blocked: the user still needs the issue, and the agent needs to read it as data.
Outbound secret scanning
scanSecrets()blocksgh pr create,git pushand generated commit messages on AWS/GitHub/Anthropic/OpenAI/Slack/Google keys, PEM headers, JWTs and generic secret assignments, with a placeholder filter to keepyour-api-key-herefrom tripping it. Matches are redacted everywhere they are reported — a guardrail report that prints the secret has just leaked it. A first push diffs from the fork point rather thanHEAD~1, which would have covered one commit out of however many the branch carried.Safety properties
CODER_GUARDRAILS=offis the single kill switch. Every path fails open: a guardrail bug must not brick tool calls, issue fetches, the memory server, or pushing. The 2 MB diff-scan cap logs what it skipped rather than letting silence read as coverage.Verification
tsc --noEmitcleanBuilt by three parallel grok workers off a shared contract commit; the joins were reviewed and hardened here.