LEAKCADE

AI agent deleted database: how to keep your production data safe

Updated 8 min read

In a reported July 2025 Replit incident, an AI agent deleted database records during a code freeze. The same thing can happen in your app if the agent holds production write credentials. Give the agent a separate development database, a role limited to the permissions it needs (least privilege) and a backup you have tested. A chat message saying "code freeze" won't stop it.

QUICK CHECKLIST

  • Give the agent a dev database, never production
  • Keep production URLs out of local .env files
  • Use a read-only or limited role for agent work
  • Read every migration before it runs
  • Turn on backups and restore one to a test project
  • Enforce code freezes with access, not prompts

The reported case: AI agent deleted database during a code freeze

In July 2025 Jason Lemkin, founder of the SaaStr community, posted that a Replit AI agent had deleted his production database. According to The Register, he also said it ignored instructions to freeze code and invented data. TechTarget reports that the agent falsely claimed the database couldn't be rolled back.

Replit's CEO, Amjad Masad, called the experience "Unacceptable and should never be possible." He said Replit keeps backups with one-click restore, promised a postmortem, and announced automatic separation of development and production databases. Replit's own blog post, as quoted by The Register, said apps had used a single database for both development and live customer data.

Prompt rules vs real limitsTwo lanes. The wrong setup gives the agent production credentials and relies on a chat instruction, so a destructive command succeeds. The right setup gives it only a dev database and a limited role, so production stays intact.WRONG SETUP1Agent holds prodDB credentials2You type: nochanges, codefreeze3Agent runs adestructivecommand4Nothing in theDB says noRIGHT SETUP1Agent only seesa dev database2Its role can'ttouch prod3Destructivecommand hits dev4Prod is fine,restore istestedWRONG SETUP1Agent holds prod DB credentials2You type: no changes, code freeze3Agent runs a destructive command4Nothing in the DB says noRIGHT SETUP1Agent only sees a dev database2Its role can't touch prod3Destructive command hits dev4Prod is fine, restore is tested
A chat prompt is a request. A database role is a limit.

We only know this from public reports, so treat the details as reported. The lesson doesn't depend on them. Forrester analyst Andrew Cornwall told TechTarget: "Software development should never rely on AI guardrails alone."

What goes wrong when an agent holds write access

An agent runs commands with whatever credentials it can reach. In most vibe coded projects that means the DATABASE_URL in .env.local, or one exported in your shell. If that URL points at production, every command the agent runs is a production command.

Lemkin's own takeaways, as reported by The Register, were that AI systems fabricate data when they fail and that AI will make changes you didn't request. With a write-capable connection, that can look like this:

The agent's own account of what happened can be wrong. Check the dashboard and the backup list yourself.

Split dev and prod, and add a Postgres read only role

Replit's docs now describe a development database where you and Agent experiment, and a production database the Agent can't modify directly. There is a catch: when you publish, schema changes the Agent made in development, including deleted columns and tables, are applied to production. Review them before every publish.

You can build the same wall on any Postgres host. Keep a separate development and production database, and keep the production connection string out of the project folder.

BEFOREProduction URL in a file the agent can read
# .env.local
DATABASE_URL=postgresql://postgres:YOUR_PASSWORD@db.live-host.example.com:5432/postgres
AFTERDev database locally, prod only on the host
# .env.local (dev only, throwaway data)
DATABASE_URL=postgresql://agent_dev:YOUR_DEV_PASSWORD@localhost:5432/myapp_dev

# The production URL lives only in your host's
# environment settings, never on your machine.
If the agent can read a production URL, it can use it.

Next, give the agent a role that can only read. Postgres grants each privilege on its own, so SELECT can be given without DELETE or TRUNCATE.

create role agent_readonly login password 'YOUR_STRONG_PASSWORD';
grant connect on database myapp to agent_readonly;
grant usage on schema public to agent_readonly;
grant select on all tables in schema public to agent_readonly;
alter default privileges in schema public grant select on tables to agent_readonly;
revoke create on schema public from agent_readonly;

Run it as an admin in psql or the Supabase SQL editor, then put agent_readonly in the agent's connection string. The alter default privileges line covers tables that the role running it creates later.

Functions marked security definer run with their owner's rights and can change data. Postgres also grants execute on functions to everyone by default, so review them and revoke execute from public on any that write.

The owner of a table can drop it, and the Postgres docs say that right can't be granted or revoked. Superusers skip privilege checks entirely. The agent must never connect as either.

If the agent must write in development, create a separate dev role with select, insert, update, delete on dev tables only, and leave out truncate. A DELETE without WHERE still works, so use it only on throwaway data. The Supabase service_role key bypasses row level security, so never hand it to the agent. See Supabase delete policies.

How to stop an AI agent deleting your database, step by step

Do these in order. The first three remove the damage an agent can do, and the rest limit how long a mistake lasts.

  1. Use two databases

    Create a separate development database, or a separate Supabase project, and point local work at it. Replit creates a separate production database when you publish. Schema changes made in development still reach production on publish, so review them first.

  2. Keep production credentials off your laptop

    Store the production connection string only in your host's environment settings. Also check what else the agent can reach: logged-in CLIs (Supabase, Vercel, Neon), personal access tokens, MCP servers connected to production, and the service role key.

    Keep .env files out of git, as covered in .env file leaks on Vercel and Netlify. If a production URL ever sat in a file an agent could read, regenerate the credentials. Rotating keys after a breach shows the order.

  3. Give the agent least privilege

    Least privilege means only the permissions the task needs. Use the read-only role for exploring data and a dev-only role for writing. Review the tool permissions in your editor too, using the Cursor and Claude Code security checklist.

  4. Read every migration before it runs

    Ask the agent to write migration files, not apply them. Look for DROP, TRUNCATE, removed or renamed columns, type changes and new required columns without defaults. Test on an isolated copy before real users see them.

  5. Turn on backups and restore one

    Check what backups your plan includes, then restore one into a test project. Do this before launch, not after an incident.

  6. Enforce freezes with access

    When you want no changes, switch the agent to the read-only role or revoke its credentials.

For the rest of your pre-launch list, see the vibe coding security checklist.

Test it yourself

Run these only against your own databases, and start with development. They inspect your setup and change no data.

# 1. Which role does the agent use, and is it a superuser?
psql "$AGENT_DATABASE_URL" -c "select current_user, rolsuper from pg_roles where rolname = current_user;"

# 2. Can that role delete? (replace todos with one of your tables)
psql "$AGENT_DATABASE_URL" -c "delete from public.todos where false;"

# 3. Which DB hosts appear in env files? (passwords are not printed)
grep -rnoE "@[A-Za-z0-9.-]+(:[0-9]+)?/" --include='.env*' .
# Variable names only, from your shell
env | grep -iE "database_url|service_role" | cut -d= -f1

What the results mean:

Then test the restore:

  1. Restore your latest backup into a new project (see Supabase's restore to a new project docs).
  2. Open the app against it and count rows in your main tables.
  3. Reset custom role passwords, since Supabase says daily backups don't store them.

Fix prompt you can paste

Before pasting this, remove production credentials from the repo and your shell, and run the agent with terminal command approval on. The instructions below are requests, not limits.

FIX PROMPT
Audit this repo for database safety. Do not connect to any database and do not run commands that change data. Do not edit files until I approve your list.

1. Find every place a database connection string or key is defined or read: DATABASE_URL, POSTGRES_URL, SUPABASE_SERVICE_ROLE_KEY, .env files, docker-compose files, seed scripts. List file and line. Flag values that look like a production host. Show only variable names and hostnames, never secret values.
2. Find destructive commands in package.json scripts and code: DROP, TRUNCATE, DELETE without WHERE, prisma migrate reset, prisma db push with --accept-data-loss, drizzle-kit push, supabase db reset. List file and line.
3. Review migration folders for dropped or renamed columns, type changes, and required columns without defaults.
4. Write, but do not run, SQL for a read-only role and a dev-only write role.
5. Propose changes so the app reads its database URL only from environment variables.

For every finding give the file path, line number, why it is risky and the exact change you suggest. Explain each change in plain English.

Backups on Supabase and what a restore costs you

Until you restore a backup, you don't know it works. Supabase takes daily backups on Pro, Team and Enterprise plans, kept 7 days on Pro, 14 on Team and up to 30 on Enterprise. It recommends that Free projects export data with the Supabase CLI db dump command and keep off-site copies.

Point-in-Time Recovery (PITR) restores the database to a chosen moment instead of the last daily snapshot. It is an add-on that needs at least a Small compute add-on. Once you enable it, Supabase stops taking daily backups.

Restores take the project offline while they run, so plan the downtime. Backups also have gaps:

For a second pair of eyes on your repo before launch, run it through Leakcade.

Further reading

  1. Replit docs: Development and production databases
  2. The Register: Replit promises to prevent vibe coding disasters
  3. TechTarget: Replit AI agent snafu, a shot across the bow for vibe coding
  4. Supabase docs: Database Backups
  5. PostgreSQL docs: GRANT

FAQ

Did a Replit AI agent really delete a production database?

According to Jason Lemkin's July 2025 account, yes. The Register and TechTarget covered it. Replit's CEO called it "Unacceptable and should never be possible" and announced automatic separation of development and production databases. The details come from public reports, so treat them as reported.

How do I separate development and production databases for an AI agent?

Create two databases with different credentials, and give the agent only the development one. Keep the production connection string in your host's environment settings, not in local files. Replit's docs say schema changes made in development are applied to production on publish, so review them first.

How do I create a read-only user in Postgres?

Run create role ... login, then grant connect on database, grant usage on schema public and grant select on all tables in schema public. Add alter default privileges in schema public grant select on tables to cover tables created later. Never connect the agent as the table owner or a superuser.

Can I stop an AI agent with a prompt like "do not touch production"?

No. A prompt is a request, and the agent can ignore or misread it. Credentials decide what it can do, so remove its access to production.

Does Supabase back up my database automatically?

Pro, Team and Enterprise projects get daily backups, kept 7 days on Pro, 14 on Team and up to 30 on Enterprise. Point-in-Time Recovery is an add-on. Free projects get no backups, and Supabase recommends exporting with the CLI db dump command.

Want a second pair of eyes?

We review your whole repo and write a fix prompt for every finding. $19, report within an hour.

Check my repo

Leakcade is an automated check. It can miss vulnerabilities and is not a substitute for a professional security audit or pentest. Provided as is. You stay responsible for your code. Where the law allows, our liability is limited to what you paid ($19). Terms

Patch Notes by Leakcade

A short weekly email: what changed in AI coding tools, one real security mistake, one prompt you can reuse.