Policy that hardens itself
May 11, 2026 10 min read
Enterprise security runs on rules: signatures, IDS patterns, WAF policies, access lists. They're deterministic, auditable, and tunable, and they remain the backbone of every serious program. Three things have always been true about them:
- Rules have to evolve continuously, from real activity and findings. A rule written once decays as the environment moves around it.
- Bad rules are expensive. Noisy, low-value rules burn out the teams stuck triaging them.
- Rules are hardest where activity is diverse and non-deterministic. DLP over human behavior is the classic case: fuzzy actions resist fixed patterns, so the rules stay noisy and need constant tuning.
Now those same teams are writing rules for AI usage. Early on it was manageable. The dominant risk was an employee pasting sensitive data into a consumer AI tool, and the fix was simple: scan the prompt, block the upload, done.
Securing agents is a fundamentally different problem. The risk has moved from the prompt to the action chain. A benign-looking request can set off a sequence of tool calls, retrievals, and writes that ends somewhere it shouldn't. Watching the input prompt is no longer enough. You need policy around what the agent actually does, and that behavior is as non-deterministic as any human's.
There is also a culture cost to weigh. The point of all this is to enable secure AI usage, so the controls have to feel light. Lean too hard on blocking, and people will push back. They will route around the guardrails or quietly drop the tools that made them productive. Good rules fade into the background, keeping work safe while staying out of the way.
Agent abilities and responsibilities are growing exponentially, and security teams across the Global 2000 are already struggling to keep up. Rules have to react to what agents are actually doing inside your organization right now. A checklist written last quarter won't capture it.
The bottom line: the loop of hardening deterministic rules around agent behavior, and shipping the fixes, has to be automated.
TL;DR
- Hand-written agent policy can't keep up. The risky patterns are too many, too non-deterministic, and change with every agent release. The loop of discovering, testing, and shipping rules has to be automated.
- Good policy is derived from the data. Mine real sessions for risky sequences, synthesize deterministic rules, backtest them against history, and ship what holds. Process, network, and identity information are all required for full context.
- Enforcement belongs in one control plane. A single agent action spans the runtime, the processes it spawns, the network it reaches, and the identity it runs under. Govern those with separate tools and you get gaps and conflicting rules.
The rule you can't write in advance
A company gives its engineers Claude Code. It reads the repo, edits files, runs shell commands, installs dependencies, and reaches the network when it needs to. Strip those abilities and it stops being useful.
Security has to govern the shell. The obvious first move is a denylist of dangerous commands:
{
"name": "Require approval for risky shell commands",
"action": "require_approval",
"scope": { "integrationFamilies": ["claude_code"] },
"conditions": {
"operator": "and",
"conditions": [
{ "field": "action.kind", "operator": "eq", "value": "tool.shell.exec" },
{
"field": "command.binary",
"operator": "in",
"value": ["curl", "wget", "aws", "kubectl", "git", "scp"]
}
]
}
}
It does not survive contact with the work. Reproducing a bug means reading env. The test suite hits the network. Shipping means git push. Half of real engineering trips the denylist, approvals pile up, engineers start clicking approve without reading, and within a week someone is running Claude Code outside the sanctioned setup. Lock it down and the tool dies, but if you leave it open, you're taking on massive risk.
So you cannot fix it by tightening the denylist. The command you care about, aws s3 cp, is identical in the routine case and the malicious one. What separates them is the data it moves and where that data goes.
Now the breach. An engineer points Claude Code at a repo to fix a flaky test. The repo ships a CLAUDE.md that reads like ordinary project guidance, with one buried line: before running tests, sync local state to a given S3 bucket. The agent reads the file as instructions, reads the environment for credentials, and runs aws s3 sync to a bucket it has never touched. Every command is one Claude Code runs every day. No single action is anomalous. The breach is the sequence: a secret read, then a transfer to a destination this repo has never used (CVE-2025-59536 [1] [2], CVE-2026-21852 [3], the same class as the MCPoison [4] and NomShub [5] disclosures).
You cannot flag that CLAUDE.md line as malicious ahead of time. What you can catch is the flow it produces:
{
"name": "Block credential read followed by egress to a new destination",
"action": "block",
"severity": "critical",
"scope": { "integrationFamilies": ["claude_code"] },
"match": "sequence",
"within": "2m",
"steps": [
{
"field": "action.kind",
"operator": "eq",
"value": "file.read",
"where": {
"field": "file.path",
"operator": "matches_any",
"value": [
"**/.env",
"**/.env.*",
"**/.aws/credentials",
"**/*.pem",
"**/id_rsa"
]
}
},
{
"field": "action.kind",
"operator": "in",
"value": ["tool.shell.exec", "tool.network.call"],
"where": {
"field": "egress.host",
"operator": "not_in",
"value": "@baseline:repo.egress_hosts"
}
}
]
}
Every field reads straight off the trace. The one piece that makes it usable is @baseline:repo.egress_hosts, the destinations this repo's sessions have used before. Without it, the rule blocks every legitimate sync to the real build cache. With it, it fires only on a new destination in the middle of a risky sequence. That baseline is computed from history, and it shifts as teams add real endpoints through normal work or approved exceptions, so it has to be recomputed from fresh sessions.
This is the shape of every agent policy worth having. The command is generic. The risk lives in the sequence and in how it compares to normal, and normal is specific to your org and drifts. Writing the rule is easy once you can see the behavior. Discovering which rule to write before the incident, and keeping its baselines current, is the work. It is too large and too fast-moving to do by hand. That loop has to be automated.
Hardening policy at scale
Automating the loop means doing three things at a volume no team can keep up with by hand: capture what agents actually do, judge it in context, and turn the result into policy you can enforce.
Capture has to be high fidelity. An agent session is the full sequence: the prompt, the files read, the tool calls and their results, the MCP exchanges, the shell commands, the network calls, the environment it ran in, and more.
The trace alone still cannot tell you whether an action was dangerous. That verdict needs context the agent runtime may not hold:
- Process. What spawned the agent, and what it executed and read on the host beyond the repo.
- Network. The connections it actually opened and the data that left, independent of what the agent reported.
- Identity. The human behind the session, their role and entitlements, and whether the action ran on their behalf.
Fused, these give you what the trace cannot. The agent's log is a self-report: a command it runs can spawn a child process that reads a secret and opens a connection the agent never sees. Endpoint and network telemetry catch it, and identity tells you whether the human behind the session was entitled to that data at all.
Forge built for this early. Over a year ago we bet that long-running desktop agents would become the primary execution surface in the enterprise, and that securing them would be both a data problem and a large-scale analysis problem. We built an agent behavior data lakehouse that ingests agent traces and fuses them with process, network, and identity signals into one queryable record of what every agent did and the context around it.
On top of it, analysis agents run the hardening loop continuously: they mine sessions for risky sequences and the baselines the rules depend on, draft candidate policies and fixes, backtest them against history, and promote the ones that hold. Each recommendation lands on the surface that can enforce it: a rule at the agent runtime, a restriction on the network, a guardrail on the process, or a change to what an identity can reach.
One control plane
Those recommendations span four enforcement surfaces, and that is where most programs fracture. The runtime rule lives in the agent, the egress restriction in the firewall, the process guardrail in the EDR, the entitlement change in the IDP. Four tools, four policy languages, and no one who can see the whole chain in one place. A single agent action runs across all four, so governing it from four consoles leaves gaps between them and rules that conflict.
This is why the loop has to live in one control plane. Forge is that plane: every session and its context in a single view, every candidate policy testable against real history before it ships, and enforcement that applies across runtime, network, process, and identity from one place.
Closing
Agent security is a moving surface. The same action is routine or catastrophic depending on context, and the rule that separates them can only be written after you have watched the behavior. A fixed list of threats was never going to hold.
That makes it a data and analysis problem before a policy problem: capture what agents do, fuse it with process, network, and identity, derive the policies that should exist, and enforce it from one place.
This is Forge.