An AI agent ran prisma migrate reset on production. What actually stops it?

Prisma has its own check for AI agents. We ran it inside Claude Code, then went around it three ways. One fix held every time: a database role that can't drop what it doesn't own.

The short answer

If a coding agent can reach your production DATABASE_URL with the role that owns the tables, prisma migrate reset will empty it. Prisma 6.15 and later refuse migrate reset and db push --force-reset from agents they detect, until you consent.34 That check is real and useful, but it can be stepped around. The fix that holds is a database role that doesn’t own the schema, so the reset fails with a permission error.

Below: what happened in the public cases, a run of Prisma’s check inside Claude Code, three ways past it, and the role that stopped all three.

Deedglass reads what Postgres actually committed, not what the agent reported. In our demo a hidden trigger turned 1 row into 301; a person countersigned the undo and all 301 rows came back.

What happened in the public cases

Two reports on the Claude Code issue tracker describe the pattern. In one, filed on 19 March 2026, the agent ran prisma db push --force-reset against a production database.1 In the other, filed on 11 March 2026, a destructive prisma db push ran against production.2 Neither involved an exotic attack. The .env file pointed at production, the agent was asked to change the schema, and a command that resets the database was the shortest path to “in sync”.

A third report shows how a reset can arrive by a side door. In claude-code#80868, a compound command passed DATABASE_URL from .env as --shadow-database-url to prisma migrate diff, no prompt appeared despite ask rules for Prisma commands, and the production database was wiped, then restored from a nightly backup.8 Prisma resets a configured shadow database as part of its work.5

What these have in common: the credential the agent held could drop every table, and nothing between the agent and the database said no.

What Prisma’s own check does

Prisma added a guard in ORM 6.15.0, released on 27 August 2025. Its announcement names Claude Code, Gemini CLI, Qwen Code, Cursor, Aider and Replit as tools that get an explicit confirmation step.3 The current docs say the agent should explain the action, warn that it destroys all data, and only after you consent set PRISMA_USER_CONSENT_FOR_DANGEROUS_AI_ACTION and rerun.5

We ran it. Prisma 6.19.3, a throwaway Postgres 17.11 on a laptop, one table with 200 rows, and the command sent from inside a Claude Code session:

Code What the screen or file shows, copied as is.

$ npx prisma migrate reset --force
Datasource "db": PostgreSQL database "app", schema "public" at "127.0.0.1:56101"

Error: Prisma Migrate detected that it was invoked by Claude Code.

You are attempting a highly dangerous action that can lead to devastating
consequences if it is incorrectly executed against a production database.
…
$ psql -tAc 'select count(*) from "Lead"'
200

The rest of the message tells the agent to stop, explain the command and its motive, say the data will be gone, and ask you. prisma db push --force-reset got the same refusal, and the 200 rows stayed.4

How does Prisma know? It reads environment variables. In the 6.19.x source, Claude Code is detected by CLAUDECODE, Gemini CLI and Qwen Code by GEMINI_CLI, Cursor by CURSOR_AGENT, Aider by OR_APP_NAME, Replit by REPLIT_CLI and Codex CLI by CODEX_SANDBOX. The check runs for migrate reset and for db push --force-reset.4 If the consent variable is set to anything at all, the command goes ahead.4

That design is sensible for what it is: a speed bump that turns a silent reset into a question the agent has to bring back to you. It is not a permission system, and Prisma doesn’t claim it is.

Where the check stops

We tried three ways past it on the same database. Each time we put the 200 rows back first.

Attempt What we ran Rows after
Consent variable set to x PRISMA_USER_CONSENT_FOR_DANGEROUS_AI_ACTION=x npx prisma migrate reset --force 0, in 1.4 s
Agent variable not passed env -u CLAUDECODE npx prisma migrate reset --force 0
A command the check doesn’t cover npx prisma db push --accept-data-loss, after removing email from the schema 200 rows, but the email column and its 200 values gone, in 28 ms, no question asked

4

The first is the one to worry about. The variable is meant to carry your words, but nothing checks that it does; an agent that reads the error can set it itself. The second happens whenever the agent’s environment doesn’t reach the process: a remote shell, a script launched by another tool, a CI job. The third is by design: --accept-data-loss tells Prisma to ignore its data-loss warnings, and --force-reset resets the whole database before pushing.6

And Prisma is one tool. drizzle-kit push --force accepts every data-loss statement without asking, and alembic downgrade base reverts every revision back to an empty schema.11 Prisma’s own team makes the same point: their newer stack has no reset command at all, and they concede that no tool can stop a process holding the keys from opening a raw connection.7

The fix that held: a role that can’t drop

In Postgres, only a table’s owner, its schema’s owner or a superuser can drop it.12 So we gave the app a role that can read and write rows but owns nothing:

Code A database command in SQL. The text around it says what it does.

CREATE ROLE app_rw LOGIN;
GRANT USAGE ON SCHEMA public TO app_rw;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_rw;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO app_rw;

Then the worst case: the consent variable set, the URL pointing at app_rw.

Code What the screen or file shows, copied as is.

$ PRISMA_USER_CONSENT_FOR_DANGEROUS_AI_ACTION=x \
  DATABASE_URL="postgresql://app_rw@127.0.0.1:56101/app" \
  npx prisma migrate reset --force
Error: P3016

The fallback method for database resets failed, meaning Migrate could not
clean up the database entirely. Original error:
ERROR: must be owner of table _prisma_migrations

$ psql -tAc 'select count(*) from "Lead"'
200

db push --force-reset failed the same way, and db push --accept-data-loss stopped at must be owner of index. All 200 rows and the email column stayed.4 No hook, no prompt, no environment variable: the database refused.

The cost is that app_rw can’t run migrations either. That’s the point. Keep a separate owner role for migrations, used by your deploy pipeline or by a person, and never put its URL where the agent can read it. Our guide to giving Claude Code or Cursor write access to Postgres has the full role setup, column grants and row-level security, with nothing to install.

A role doesn’t help with DELETE FROM on tables it can write, of course. For that, see how big a mistake an agent can make and the post on safe Postgres access for AI agents.

Keep the production URL away from the agent

Every public case starts with a production URL in a file the agent reads. Three habits close that door:

  • Point .env at a local or branch database. Production credentials live in your deploy platform’s secrets, not in the repository’s working tree.
  • Deny reads of .env in the agent. In Claude Code a Read deny rule such as Read(.env) matches at any depth and covers Claude’s file tools and recognised file commands like cat, though not a program that opens the file itself.9
  • Don’t trust ask rules alone. Claude Code checks deny, then ask, then allow, and ask rules apply when any part of a compound command matches.9 Even so, #80868 shows a compound command that wiped a database with ask rules in place.8

A hook as the second check

A hook reads each shell command before it runs, whatever environment variables the process gets. This is the Deedglass shell guard, v0.9.0, on the commands from the cases above:

Code What the screen or file shows, copied as is.

$ deedglass guard shell --command "npx prisma db push --force-reset"
Deedglass asks first: prisma db push --force-reset resets the database before it
pushes the schema, which deletes every row.

$ deedglass guard shell --command "cd api && PRISMA_USER_CONSENT_FOR_DANGEROUS_AI_ACTION=yes npx prisma migrate reset --force"
Deedglass asks first: prisma migrate reset drops the database, or every table in
it, and applies your migrations again, so its data is gone.

$ deedglass guard shell --command "npm run db:fresh"
Deedglass asks first: prisma migrate reset (in npm run db:fresh) drops the database,
or every table in it, and applies your migrations again, so its data is gone.

The consent variable doesn’t switch it off, and the last line comes from reading the package.json script that npm run would start.10 As a Claude Code PreToolUse hook it answers ask, never allow, and needs no server or account.10

Its limits are the reason it’s the second check, not the first. It reads the command as written and doesn’t run it, and if it can’t run at all, the command goes ahead unchecked.10 It only knows the commands in its catalog, so a reset hidden in a compiled binary or a script it can’t read gets through. A role that owns nothing doesn’t have those gaps.

A checklist

  1. The URL in .env points at a local or branch database, never production.
  2. The app and the agent connect as a role that owns no tables.
  3. Migrations run as a separate owner role, from CI or by a person.
  4. Prisma is 6.15 or later, so detected agents get the consent step.3
  5. The agent can’t read .env (a Read deny rule, or no such file in its tree).
  6. A before-a-command hook asks on reset, force and drop commands.
  7. Point-in-time recovery is on, and you have restored from it once.
  8. You know the first hour: what to do when an agent deletes the database.

Try it on your own project: npx deedglass scan reads your Claude Code settings and package.json and lists the database commands your agent could run today. Nothing leaves your machine. The hooks post shows the same guard in Codex, Gemini CLI, Copilot and Cursor. The grade is explained on /score. To watch a database change more than the statement named, try the playground, a real Postgres in a browser tab.

Questions people ask

Does Prisma stop Claude Code from running migrate reset?

Yes, from 6.15.0 on, when it detects the agent: Claude Code is detected by its CLAUDECODE environment variable, and the command stops until the consent variable is set.4 Any value works, so treat it as a prompt for the agent, not a lock.

Is prisma db push –force-reset covered too?

In the code, yes: the same check runs for db push --force-reset.4 The docs describe it for migrate reset, and db push --accept-data-loss isn’t covered.5

Can I use prisma migrate reset in production?

Not against data you want to keep. It drops or soft-resets the database and re-applies every migration, so whatever the tables held is gone.5 Run it on local or branch databases only.

What is the safest way to let an agent run migrations?

Let it write the migration file, and let a person or your deploy pipeline apply it with the owner role. The agent’s own role owns nothing, so a reset fails.

Written with AI assistance and checked against our claims register.

The takeaway

Prisma’s own AI check can be gone around; what held every time was a database role that can’t drop what it doesn’t own.

Read nextHooks that block dangerous commands in Codex CLI, Gemini CLI, Copilot and Cursor Try it: install in 7 s

Related on this site

More posts

Sources

  1. 1claude-code#36183: prisma db push --force-reset on a production database (19 March 2026) · github.com · checked 25 October 2026
  2. 2claude-code#33183: destructive prisma db push against production (11 March 2026) · github.com · checked 25 October 2026
  3. 3Prisma blog: ORM 6.15.0, AI safety guardrails for destructive commands (27 August 2025) · prisma.io · checked 25 October 2026
  4. 4prisma/prisma 6.19.x: packages/migrate/src/utils/ai-safety.ts · github.com · checked 25 October 2026
  5. 5Prisma docs: migrate reset · prisma.io · checked 25 October 2026
  6. 6Prisma docs: db push · prisma.io · checked 25 October 2026
  7. 7Prisma blog: Don't let your AI agent delete your production database (30 July 2026) · prisma.io · checked 25 October 2026
  8. 8claude-code#80868: ask rules skipped, production wiped through --shadow-database-url (24 July 2026) · github.com · checked 25 October 2026
  9. 9Claude Code docs: permissions · code.claude.com · checked 25 October 2026
  10. 10Deedglass docs: the shell guard · docs.deedglass.com · checked 25 October 2026
  11. 11Drizzle docs: drizzle-kit push · orm.drizzle.team · checked 18 October 2026
  12. 12PostgreSQL 17 docs: DROP TABLE · postgresql.org · checked 25 October 2026

Published 25 October 2026, sources last checked 25 October 2026. If something here is out of date, write to hello@deedglass.com.

Try it on your own setup

npx deedglass scan

Grades only your own setup. Nothing is uploaded.

Pricing