Securing Your AI Coding Agent Before It Ships Something You'll Regret
I've been burned by this twice. You give an AI coding agent access to your repo, it helpfully "fixes" something adjacent to your request, and suddenly you're staring at a git diff that touches files you never intended. The agent wasn't malicious — it was doing exactly what it was designed to do: be helpful. But helpful without boundaries is how you end up with an agent that reads your .env file to "understand the codebase context" or makes outbound requests to verify an API key it just found.
The second time it happened, the agent was running in a CI pipeline with elevated permissions. It autocompleted a refactor that renamed a config key — across 12 files — in a way that broke production for about 40 minutes. Again, nobody's fault in a traditional sense. But nobody had defined what the agent was actually allowed to touch, read, or execute. That gap between "agent has access" and "agent has scoped, auditable access" is where incidents live.
What Most Teams Try First
The common pattern is bolting security on after the fact: wrapping the agent call in a try/catch, adding a human approval step in the UI, or just telling the agent in the system prompt to "be careful with sensitive files." None of these are wrong, but they're incomplete. Prompt-based restrictions are easily bypassed by context drift over long conversations. Manual approval gates slow iteration without providing real audit trails. And without filesystem sandboxing or permission manifests, you're relying entirely on the model's judgment about what counts as "sensitive."
A More Structured Approach
The core of a solid agent security setup is a permission manifest — a machine-readable definition of what the agent can read, write, execute, and call. Think of it like a robots.txt but with actual enforcement. You define scopes per task type, and the agent runtime checks permissions before each tool call rather than after.
{
"agent_permissions": {
"read": ["src/**", "tests/**"],
"write": ["src/**"],
"deny": ["**/.env*", "**/secrets/**", "**/*.pem"],
"exec": ["npm test", "npm run lint"],
"network": "none"
}
}
This manifest gets validated at the tool layer, not in the prompt. If the agent tries to read ~/.ssh/config or execute an arbitrary shell command, it gets a structured error back — not a hallucinated success. That error also gets logged with the full tool call context, so you have a real audit trail.
The second component is session-scoped credential isolation. Agents that need API access should receive short-lived, scoped tokens generated at session start — not ambient credentials from the environment. This means a compromised or misbehaving agent session can be revoked without rotating your actual keys. You can implement this with any secrets manager that supports token leasing (Vault, AWS Secrets Manager with Lambda rotation, etc.).
The third piece is output validation before any write completes. This isn't just checking file extensions — it's diffing the proposed change against a set of invariants: no new network calls added to auth flows, no removal of input validation, no modification of lockfiles outside of explicitly dependency-update tasks. These rules run as a lightweight static pass between the agent's proposed change and the actual filesystem write.
Quick Start
-
Define your permission manifest — start with a
denylist covering.env*,**/secrets, certificates, and shell history before worrying about what to allow - Move credentials out of the environment before giving any agent filesystem access; use a secrets manager with session-scoped token leasing
- Instrument tool calls — log every read/write/exec with timestamp, session ID, and the agent's stated reason; you need this for incident review
-
Write three invariant rules specific to your codebase (e.g., "auth middleware files require human approval", "no new
eval()calls", "package.json changes require diff review") - Run the agent in a network-isolated container for local development; outbound calls should be explicit and logged, not ambient
- Test your deny rules by intentionally prompting the agent toward a restricted file and confirming the structured error fires correctly
The goal isn't to hobble the agent — it's to make its actions legible, bounded, and recoverable. You want fast iteration and a paper trail.
Full toolkit at [ShellSage AI](
Top comments (0)