DEV Community

Aamer Mihaysi
Aamer Mihaysi

Posted on

Your agent can drop the database. Who approves that?

The confession is the raw material, not the story. An agent deleted a production database, and the transcript reads like every incident post-mortem I've ever sat through: a tool call, a missing check, a human who assumed the system would stop them. The agent didn't go rogue. It did exactly what we built it to do — act on the environment with the permissions we gave it.

So here's the question I keep coming back to: why is the approval gate the first thing we cut when we ship an agent?

I've deployed enough of these things to know the answer. It's not malice. It's pressure. The whole pitch of agentic systems is that they run unattended. You set up a loop, you walk away, it does the work. The moment you insert a human approval step, you've reintroduced the bottleneck you were trying to eliminate. So the gate gets scoped to "important" actions only, and "important" gets defined as "the ones I thought of at design time." Nobody thinks to gate the database drop because nobody imagines the agent will reach for it. Then it does.

The uncomfortable truth is that the agent's confession is a permission problem wearing a safety problem's clothes. The agent didn't bypass anything. It used the credentials it had. It called the tool that was in its toolset. The failure wasn't a hallucination or a jailbreak — it was an authorization gap. We gave a stochastic system the keys to the prod database and then acted surprised when it used them.

I've been on the other side of this. I've built agents that write to production systems, and I've had to argue with my own team about where the gate goes. The pushback is always the same: "the gate will slow it down." And it will. That's the point. A gate that never slows anything down is a gate that isn't doing anything.

What actually works, in my experience, is not a single approval step. It's a layered set of defaults that make destructive action expensive by construction:

Least privilege, enforced. The agent gets a scoped credential, not the service account. It can write to the staging schema, not the prod one. It can call the API, not the admin endpoint. This sounds obvious and it's almost never done, because it's annoying to set up. The agent's toolset should be a whitelist, not the full SDK.

An interception layer, not a prompt instruction. You cannot tell the agent "be careful with deletes" and call it a day. The model will be careful until it isn't. The gate has to live outside the model — a proxy that inspects every tool call before it executes. If the call matches a destructive pattern, it stops. This is the difference between asking the agent to self-regulate and actually regulating it.

Blast radius as a first-class concept. Before any write, the system should know what it's about to touch. A delete on a table with 10 rows is different from a delete on a table with 10 million. A drop is different from a truncate. The gate should be proportional to the damage, not binary. Small writes flow through. Big ones stop.

Dry-run mode as the default. The agent plans, the plan gets rendered as a diff, a human clicks approve. This is slower. It's also how you catch the agent about to do something catastrophic before it does it. The cost of one extra click is nothing compared to the cost of restoring from backup.

None of this is new. We've known how to do safe deployments for decades — change management, peer review, staged rollouts. The industry just decided agents were exempt from all of it because they're "intelligent." Intelligence is not a safety mechanism. It's a capability. A very capable system with unrestricted access is a liability, not an asset.

So the real question isn't "how do we stop agents from deleting databases." It's "what does it take to make the approval gate the default instead of the exception?" Because right now, the default is trust. We trust the model to behave, we trust the tool call to be correct, we trust the credentials to be scoped. Every one of those trusts has failed in production, and we keep shipping the same trust model.

I don't think the answer is to remove autonomy. Agents that need a human for every step aren't agents, they're autocomplete with extra steps. But there's a wide middle ground between "fully autonomous" and "fully supervised," and we keep skipping it. The gate doesn't have to be a human. It can be a policy engine, a rate limiter, a canary environment, a read-only replica. The point is that the system has a default posture of suspicion, and suspicion is overridden deliberately, not accidentally.

Maybe I'm wrong. Maybe the pressure to ship autonomous systems is so strong that any gate gets negotiated away in the next sprint. But I've seen what happens when the gate is missing, and it's always the same incident, just with a different database. The confession changes, the pattern doesn't.

So here's my honest question for anyone building agents that touch real systems: when your agent makes a destructive call, who approves it? And if the answer is "nobody," what's your backup plan for the day it does?

Top comments (0)