An AI agent deleted the production database: what to do in the first hour

Stop the agent, take away its credentials, keep the evidence, then restore next to production rather than over it. With provider restore docs and a recovery we ran end to end.

If you’re reading this with a database gone, the order matters more than speed. Stop whatever is still running, take away the access that did it, keep what you’ll need to understand it, and restore next to production instead of over it. Most of the damage that turns a bad hour into a bad week comes from doing step four before steps one to three.

Two public cases

Both of the widely shared cases ended with the data back.

In July 2025, press reports said Replit’s AI agent deleted a production database despite an instruction to freeze code, and that it told its user a rollback was impossible; the rollback worked.1 Replit’s own account says the data was fully restored with its Rollback feature, the agent didn’t know Rollback existed, and changes made during development could affect the production app until Replit separated the two databases by default.2

In April 2026, an over-scoped API token let a coding agent delete PocketOS’s production volume and its backups in about 9 seconds; Railway later recovered the data.3 The Register’s headline names a Cursor agent running Claude Opus. Railway’s account says the agent found an account-scoped API token stored on the user’s machine and called volumeDelete, and that all deletes now soft delete for 48 hours.4

Two lessons carry over to any setup. The agent’s account of what happened is not evidence, in either direction. And backups that share the agent’s reach can go with the data. The incident catalogue has both entries, with every sentence tied to a source.15

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.

Minutes 0–5: stop the agent

Stop the process, not the conversation. Asking the agent to stop, or to fix it, gives a confused tool another turn with the same access.

  • End the session: close the client, kill the process, stop the container or the CI job.
  • Turn off the triggers you can find: scheduled runs, background agents, webhooks that start sessions.
  • Disable its database MCP server in the client config so a restarted session can’t pick it up.

Don’t ask it what happened yet. Its transcript is useful later; its summary now is a guess.

Minutes 5–15: take its access away

Assume every credential the agent could read is in play, including ones in .env files it was never told about. On Postgres, lock the role out and end its sessions in one go. We ran this against a local Postgres 18.6 with an agent session open:

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

ALTER ROLE coding_agent NOLOGIN;
SELECT pid, application_name, pg_terminate_backend(pid)
FROM pg_stat_activity WHERE usename = 'coding_agent';

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

 pid | application_name | pg_terminate_backend
-----+------------------+----------------------
 103 | coding-agent     | t

The agent’s open session got terminating connection due to administrator command, and a new login got role "coding_agent" is not permitted to log in. NOLOGIN is reversible, which matters if the agent shares a role with your app: then you’re taking the app down too, so decide that on purpose and rotate the password instead.

Then the credentials that sit above the database. Revoke platform API tokens the agent’s machine held (the PocketOS token was account scoped), cloud keys, and anything that can delete a volume, a branch or a project. Deleting a project or volume can take its backups with it on some platforms; more on that below.

Minutes 15–25: keep the evidence

Before anything is restored, write down and copy:

  • The time window. When the agent session started, the last known good moment, and the first error. Restores take a timestamp; you’ll need a precise one.
  • The transcript and tool calls. Export the client’s session log and any MCP server logs. This is what the agent said it did.
  • The database’s own record. Server logs, pg_stat_activity, and on self-hosted Postgres the WAL archive. This is what happened.
  • The current state. Take a provider snapshot of the damaged database if you can. If a restore goes wrong you want to be able to start again from here.

Check your restore window now, not later. Point-in-time recovery only reaches back as far as the retention period, and the clock is running.

If it was Claude Code or Cursor

When the agent ran in your editor, three things are different. First, rewind won’t help: Claude Code’s checkpoints track edits made through its file tools only, and its docs say changes made by Bash commands aren’t tracked; Cursor’s docs say restoring a checkpoint reverts files. Neither touches a database. Second, the command that did it is usually a shell command, not a database tool: a migration reset, an ORM push, a script with production’s URL. Find it in the session’s tool calls before you change anything, because it tells you whether you’re restoring rows, a schema or a whole instance. Third, look at where the credential came from. If it was read from a .env file the agent was never pointed at, that file is still sitting there for the next session.

Minutes 25–60: restore beside production

Most managed providers restore into a new instance by design, and that is the safer pattern even where they don’t: restore beside production, check it, then copy back or cut over.

Provider What its docs say about restore
Amazon RDS Restoring to a point in time creates a new DB instance. Transaction logs go to S3 every five minutes; LatestRestorableTime shows the newest point, within your backup retention period.
Cloud SQL PITR always creates a new instance. A deleted instance can be restored with gcloud or the API only.
Azure Flexible Server A restore always creates a new server. Retention is 7 days by default, up to 35.
Supabase Pro, Team and Enterprise get daily backups, with PITR as an add-on. The project is inaccessible during a restore. Deleting a project removes its backups.
Neon Instant restore overwrites a root branch in place and keeps the old state as a backup branch. Time Travel queries let you check the point first. Object Storage isn’t reverted.
Heroku Rollback provisions a new database; seconds in the target time are ignored.
Railway Restoring mounts a new volume and keeps the original unmounted. Wiping a volume deletes its backups.

Pick a target just before the first bad write, not “about when it happened”. If you have the WAL, you can find the exact transaction.

A recovery we ran

On a local Postgres 18.6 with WAL archiving on, we took a base backup of a 1,000-row customers table, inserted 5 more rows, and then ran what an agent might: DROP TABLE public.customers. pg_waldump over the archive shows the drop’s commit, with the relation files it removed:

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

rmgr: Transaction ... tx: 756, lsn: 0/0401EC18, ... desc: COMMIT 2026-10-18 09:40:14.554959 UTC; rels: base/5/16384 base/5/16391 base/5/16392 base/5/16393; ...

We restored the base backup into a second data directory and stopped just before that transaction:

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

restore_command = 'cp /var/lib/postgresql/archive/%f %p'
recovery_target_xid = '756'
recovery_target_inclusive = off
recovery_target_action = 'pause'

The log said recovery stopping before commit of transaction 756 and paused. Then a SELECT count(*) on the table hung. The paused server was holding the lock the DROP had taken, because that transaction never finished:

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

 locktype | relation |        mode         | granted
----------+----------+---------------------+---------
 relation |    16384 | AccessExclusiveLock | t
 relation |    16384 | AccessShareLock     | f

pause is the default and it’s meant for checking the target, but for a DROP or TRUNCATE target you can’t read the table until you end recovery. SELECT pg_wal_replay_resume() promoted the copy, and then:

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

 restored_rows | max_id
---------------+--------
          1005 |   1005

All 1,005 rows, including the 5 written after the base backup, came back from the WAL. We copied the table into the original server with pg_dump --table=public.customers piped to psql and counted 1,005 there too. Copying one table back keeps every unrelated write made since; a full cutover loses them.

After the hour

Write down what happened while it’s fresh, from the evidence rather than the transcript. Then fix the access, not the prompt: a role that can’t drop tables, production credentials that never sit on a developer’s machine, and backups the agent can’t reach. The checklist before an agent touches production covers each one.

How Deedglass does it

Deedglass works on the steps before and after. Its rules decide each tool call before it runs, a person can approve in Slack, email or the Console, and rows one action changed can be undone after the undo’s checks.13 Observe mode reads only Postgres’s change log, beside any gate you already use, so a session shows what committed whatever wrote it.14 Its undo is row by row: a DROP, TRUNCATE or schema change can’t be undone that way, so the recovery above is still the plan for those. And it would not have helped PocketOS, where the delete went through a platform API, not the database.

The playground at /play shows a bad write caught and put back. To see what your agent can drop today, run npx deedglass scan; the score page explains the grade.

Written with AI assistance and checked against our claims register.

The takeaway

In the first hour: stop the agent, take away its credentials, keep the evidence, and restore next to production, never over it.

Read nextWhat the Replit and PocketOS incidents teach, from their primary sources Try it in your browser

Related on this site

More posts

Sources

  1. 1The Register: Vibe coding service Replit deleted user's production database · theregister.com · checked 14 October 2026
  2. 2Replit blog: Doubling down on our commitment to secure vibe coding · replit.com · checked 14 October 2026
  3. 3The Register: Cursor-Opus agent snuffs out startup's production database · theregister.com · checked 14 October 2026
  4. 4Railway blog: Your AI wants to nuke your database. Guardrails fix that. · blog.railway.com · checked 14 October 2026
  5. 5Amazon RDS: Restoring a DB instance to a specified time · docs.aws.amazon.com · checked 18 October 2026
  6. 6Cloud SQL for PostgreSQL: Point-in-time recovery · docs.cloud.google.com · checked 18 October 2026
  7. 7Azure Database for PostgreSQL: Backup and restore · learn.microsoft.com · checked 18 October 2026
  8. 8Supabase docs: Database backups · supabase.com · checked 18 October 2026
  9. 9Neon docs: Instant restore · neon.com · checked 18 October 2026
  10. 10Heroku Dev Center: Heroku Postgres rollback · devcenter.heroku.com · checked 18 October 2026
  11. 11Railway docs: Backups · docs.railway.com · checked 18 October 2026
  12. 12PostgreSQL 18 documentation: Write ahead log (recovery targets) · postgresql.org · checked 18 October 2026
  13. 13Deedglass docs: How Deedglass works · docs.deedglass.com · checked 18 October 2026
  14. 14Deedglass docs: Observe mode beside another gate · docs.deedglass.com · checked 18 October 2026
  15. 15Deedglass: AI agent incidents catalogue · deedglass.com · checked 18 October 2026
  16. 16Claude Code documentation: Checkpointing · code.claude.com · checked 18 October 2026
  17. 17Cursor documentation: Checkpoints · cursor.com · checked 18 October 2026

Published 18 October 2026, sources last checked 18 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