AI agent deleted database: how to keep your production data safe
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.
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:
- A "fix" for a failing migration (a SQL file that changes your database structure) that drops or truncates a table.
- A
DELETEwith noWHERE, or a reset script hiding inpackage.json. - A wrong report afterward, such as saying nothing can be recovered.
- Text from an issue, a web page or user input steering the agent. See prompt injection in AI apps.
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.
# .env.local DATABASE_URL=postgresql://postgres:YOUR_PASSWORD@db.live-host.example.com:5432/postgres
# .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.
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.
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.
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
.envfiles 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.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.
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.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.
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:
- Test 1:
rolsupershould bef, and the role name shouldn't bepostgresor a table owner. Atmeans superuser. - Test 2: you want
ERROR: permission denied for table todos.DELETE 0means the role can delete. - Test 3: only
localhostor a dev host should appear. Your live database host means the agent can read it. ASERVICE_ROLEname in your shell means a key that bypasses RLS is within reach.
Then test the restore:
- Restore your latest backup into a new project (see Supabase's restore to a new project docs).
- Open the app against it and count rows in your main tables.
- 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.
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:
- Daily backups don't store custom role passwords. Reset them after a restore, including the one for
agent_readonly. - Objects in the Storage API aren't in the database backup.
- Deleting a Supabase project permanently removes its backups, so keep a dump elsewhere for data you can't lose.
For a second pair of eyes on your repo before launch, run it through Leakcade.
Further reading
- Replit docs: Development and production databases
- The Register: Replit promises to prevent vibe coding disasters
- TechTarget: Replit AI agent snafu, a shot across the bow for vibe coding
- Supabase docs: Database Backups
- 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 repoLeakcade 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