AI coding agent admin guide·verified October 21, 2026

stop ai coding agents from deleting your production database

Agents have dropped production databases through SQL, ORM migrations and Terraform. Block the commands that do it, on every developer machine, and bound the credentials.

the short answer

Deny the commands that destroy data before they run, on every machine: DROP and TRUNCATE, unbounded DELETE, dropdb, ORM resets like prisma migrate reset and drizzle-kit push --force, rails db:drop, and terraform destroy. Keep production connection strings out of agent context. Then make sure the credentials an agent can reach cannot drop production at all. Policies stop the likely path; credentials bound the worst case.

Paths to deletion
SQL, ORM migrations, framework tasks, Terraform, cloud CLIs
Deny
Destructive operations against production targets
Hide
.env.production and connection strings from the agent
Bound
No production write credentials in agent sessions
Evidence
Public incidents in 2025 and 2026, including Replit

How Agents Actually Delete Databases

The common thread: the agent had a connection string or cloud credentials for production in its environment, and nothing checked the command before it ran.

RouteExampleReported in
Schema push with forcedrizzle-kit push --forceclaude-code #27063
Infrastructure destroyterraform destroy removing the database resourceHN: “Claude Code wiped our production database with a Terraform command”
Direct SQLDROP TABLE, TRUNCATE, DELETE FROM usersReplit incident, July 2025
ORM resetprisma migrate reset, rails db:drop db:createCommon in local setups pointed at the wrong URL
Cloud CLIaws rds delete-db-instanceAny agent with an admin profile

A Policy That Covers the Main Routes

It always denies terraform destroy and cloud database deletes. For SQL, ORM and framework commands it denies when the command names a production target. Otherwise it returns instruct: the command still runs, and the agent reads guidance to check its target. That is deliberate, because the same command against a local database is usually legitimate; if you want a hard stop everywhere, change that branch to deny.

The coding agent pack also has warn-destructive-sql, off by default (failproofai policies add warn-destructive-sql), which warns on DROP, TRUNCATE and DELETE without WHERE. With Jev on and the FailproofAI/jev-policies pack installed, its database-destruction check also asks whether the target is a real database rather than a disposable one.

import { customPolicies, allow, deny, instruct } from "failproofai";

// Cloud and infrastructure deletes never target a local database.
const ALWAYS_DENY = [
  /\bterraform\s+destroy\b/,
  /\b(rds|dynamodb)\s+delete-/,
];
const DESTROY = [
  /\b(drop\s+(table|database|schema)|truncate(\s+table)?\s+[\w."`]+)/i,
  /\bdelete\s+from\s+[\w."`]+\s*(?:;|["'`]|$|where\s+(1\s*=\s*1|true)\b)/i,  // DELETE with no real WHERE
  /\bdropdb\b/,
  /\bprisma\s+(migrate\s+reset|db\s+push\b.*--(force-reset|accept-data-loss))\b/,
  /\bdrizzle-kit\s+push\b.*--force\b/,
  /\b(rails|rake)\s+db:(drop|reset|purge|schema:load)\b/,
  /\bdrop(Database|Collection)\s*\(|\.drop\s*\(\s*\)/,                             // MongoDB
];
// A whole word, so PROD_URL and .primary match but "products" does not.
const PROD = /(^|[^a-z])(prod|production|primary)([^a-z]|$)/i;

customPolicies.add({
  name: "protect-production-data",
  description: "No destructive database operations against production from agents",
  match: { events: ["PreToolUse"] },
  fn: async (ctx) => {
    if (ctx.toolName !== "Bash") return allow();
    const cmd = String(ctx.toolInput?.command ?? "");
    if (ALWAYS_DENY.some((re) => re.test(cmd))) {
      return deny("Agents do not delete cloud databases or destroy infrastructure. Describe the change in a PR.");
    }
    if (!DESTROY.some((re) => re.test(cmd))) return allow();
    if (PROD.test(cmd)) {
      return deny("Destructive database operation against production. A human must run this.");
    }
    return instruct("This destroys data. Check that it targets a local or test database before relying on the result.");
  },
});

Test Before You Trust It

Run each row with fp policies test ./protect-production-data.policy.mjs --command "<command>" --expect <decision>, and backtest the draft in Admin → policy editor against your fleet’s recent traffic before publishing.

CommandExpected
psql "$PROD_URL" -c "DROP TABLE users"deny
rails db:drop RAILS_ENV=productiondeny
psql "$PROD_URL" -c "TRUNCATE users"deny
psql "$PROD_URL" -c "DELETE FROM users WHERE 1=1"deny
dropdb productiondeny
rake db:drop RAILS_ENV=productiondeny
mongosh prod --eval "db.dropDatabase()"deny
terraform destroy -target=aws_db_instance.maindeny
aws rds delete-db-instance --db-instance-identifier stagingdeny
psql "$DATABASE_URL" -c "DELETE FROM users"instruct
psql "$DATABASE_URL" -c "DROP TABLE products"instruct
npx prisma migrate resetinstruct
npx prisma db push --force-resetinstruct
npx drizzle-kit push --forceinstruct
psql -c "SELECT count(*) FROM users"allow
psql -c "DELETE FROM sessions WHERE expires_at < now()"allow

Make It Robust with a Decision-Model Check

The policy above only knows the commands it lists, and it can only tell production from a name in the command. The FailproofAI/jev-policies pack already has the decision-model checks for this: database-destruction asks whether a call destroys or mass-modifies database data, and destructive-deletion whether it permanently deletes data that cannot be regenerated. Both are deny-mode: they block on strong evidence and warn on moderate evidence.

Both checks are user-overridable, so an explicit request from the person clears them. Keep the regex policy’s production deny hard, so no prompt can talk past it.

These checks ship in the FailproofAI/jev-policies pack. Jev comes with Failproof; turn it on whenever you choose, with failproofai jev setup or a Cloud machine key that carries jev:evaluate. For rules of your own, we write custom checks.

# The 16 semantic checks Failproof publishes, including the ones named on this page
failproofai policies add FailproofAI/jev-policies
# Turn on Jev, which comes with Failproof (Cloud machine key with jev:evaluate)
failproofai jev setup --provider failproofai
failproofai jev status
  • python manage.py flush --noinput or npx knex migrate:rollback --all: destructive commands no list in the policy names.
  • psql "$DATABASE_URL" -c "DROP TABLE users": the regex only instructs, because no production target is named; the check judges whether the target holds real data.

Keep Production Connection Strings Out of Reach

  • block-env-files denies reads and writes of .env files, including .env.production, and is on by default in the coding agent pack.
  • protect-env-vars denies commands that dump the environment, where DATABASE_URL often lives; also on by default.
  • Do not export production URLs in developer shells by default. If an agent cannot see the URL, it cannot target it.

Bound the Worst Case with Credentials

Give agent sessions database users without DROP or broad DELETE on production, and cloud profiles without rds:DeleteDBInstance. Enable deletion protection on managed databases. Replit’s own fix after its incident was automatic separation of development and production databases. A policy makes deletion unlikely; credentials and deletion protection make it impossible.

FAQ

Is telling the agent “never touch production” enough?

No. In the Replit case the agent acted during an explicit code freeze. Instructions to the model are not enforcement.

Should I block all SQL from agents?

No. Agents legitimately read data and run migrations locally. Block destruction and production targets, not SQL.

Does this work in Cursor and Codex too?

Yes, for supported harnesses: Failproof normalizes the shell tool to Bash with a command field, so the same policy runs at each agent’s pre-tool gate. On Codex, make sure the hooks are trusted: failproofai config writes them into /etc/codex/config.toml when it can use sudo; otherwise approve them once in codex.

Sources

Checked against the sources below on October 21, 2026. Harness settings, hook capabilities and cloud features change between versions.

  1. claude-code issue #27063: agent ran a destructive db command and wiped a production database
  2. Hacker News: Claude Code wiped our production database with a Terraform command
  3. The Register: Replit makes vibe-y promise to stop its AI agents making vibe coding disasters (Jul 22, 2025)
  4. Prisma docs: migrate reset
  5. Failproof AI docs: Use a policy pack
  6. Failproof AI docs: Policy authority
  7. Failproof AI docs: Jev policies
  8. Failproof AI docs: Test a policy
  9. Failproof AI docs: Agent harnesses and enforcement capability
  10. AWS docs: Service control policies (SCPs)