Guides

How to Secure a Vibe Coded App Before Launch

Checked 2026-10-31

Loading poll...

To secure a vibe coded app, check six things before anyone else uses it: no secrets in the code or its history, access rules on every database table, sign-in and permissions tested with a second account, input handled safely, dependencies up to date, and backups with a restore you have actually tried. Facts checked 31 October 2026.

What you will have at the end

  • A list of what an AI-written app usually gets wrong and where to look
  • Commands that find leaked secrets and old packages
  • A two-account test that proves one user cannot see another's data
  • An access rule example for a Supabase-style database
  • A short routine to repeat before every release

Why bother: the Wikipedia article on vibe coding lists increased risk of security vulnerabilities among the main criticisms, and the risk is easy to see. A model writes code that works, and working is not the same as safe. Our page is vibe coding bad covers the wider debate. This page is the practical check.

First, decide how much is at stake

Not every app needs the same level of checking. Rank yours.

Your app

Level

What to do

A personal tool nobody else uses

Low

Secrets check and backups

A public brochure site with a contact form

Low to medium

Secrets, form handling, dependency check

An app with accounts but no sensitive data

Medium

All six checks below

An app with personal data, bookings or messages

High

All six, plus a reviewer who can read the code

An app that takes payments or handles health or legal data

Very high

A developer's review and, where rules apply, expert advice

Rules can apply whatever tool wrote the code. If you store personal information about people in regulated places, you may owe legal duties, and a prompt does not discharge them.

Check 1: Secrets

A secret is anything that grants access: API keys, database passwords, tokens, signing keys. Vibe coding tools sometimes paste a key into front-end code because it makes the demo work.

Find them. Search the working folder and the Git history.

# Quick search in files
grep -rInE "(api[_-]?key|secret|token|password)\s*[:=]" --exclude-dir=node_modules --exclude-dir=.git .

# Search the whole history with a purpose-built scanner (install first)
gitleaks detect --source . --verbose

Treat any hit with suspicion. A key that was ever committed counts as exposed, because history keeps it. Rotate it at the provider, then remove it from the code.

Keep them out. Store secrets in the host's environment settings, and read them from the environment in code. Add .env to .gitignore before the first commit. Never paste a secret into a prompt, since prompts can be stored or logged.

Know what the browser sees. Anything shipped to the browser is public. A front end cannot hold a secret at all. If the app needs a private key to call a paid service, put that call in a server or serverless function and keep the key there. Many vibe coded apps get this wrong, and the fix is one sentence in your instructions file: "Never put secret keys in front-end code."

Some keys are meant to be public. A publishable key for a database client is designed to be in the browser. What protects the data in that case is the access rules, which is the next check.

Check 2: Database access rules

This is the one that bites most often. If your app uses a hosted database with a public API, the rules on each table decide who can read and write. Without rules, anyone with the public key can.

Supabase's documentation states it directly: a table in an exposed schema without row level security is readable and writable by any role with a grant on it. It tells you to enable row level security on every table in an exposed schema, and, on projects that still grant anon and authenticated access by default, to revoke those grants, because adding policies does not remove them.

Here is the shape of a rule. Replace the table and column names with yours.

-- Turn rules on for the table
alter table public.orders enable row level security;

-- Let a signed-in user read only their own rows
create policy "Users read own orders"
  on public.orders
  for select
  to authenticated
  using ( (select auth.uid()) = user_id );

-- Let a signed-in user insert only rows that belong to them
create policy "Users insert own orders"
  on public.orders
  for insert
  to authenticated
  with check ( (select auth.uid()) = user_id );

Two things to understand. First, enabling rules with no policies blocks access for ordinary roles, which is the safe default. Second, a policy lets through only what it describes, so write one per action you want to allow.

Test it. The only convincing proof is trying to break in.

  1. Create two accounts, Alice and Bob.
  2. As Alice, create a record.
  3. Sign in as Bob. Try to open Alice's record by its address, and try to list all records.
  4. Try to edit and delete Alice's record from Bob's session.

If Bob can see, change or delete anything of Alice's, you have found a real bug, and you found it before a stranger did. Fix it and repeat the test. Our Cursor and Supabase stack shows the Supabase side of this setup.

Check 3: Sign-in and permissions

Sign-in proves who someone is. Permissions decide what they may do. AI-written apps often hide an admin button in the interface and forget to refuse the action on the server.

  • Check on the server, not only the screen. Hiding a button does not stop a person who sends the request directly.
  • Test the admin pages as a normal user. Open the admin address while signed in as an ordinary account. You should see a refusal.
  • Use the provider's sign-in. Do not let the agent invent password handling. Use your platform's or database's built-in auth.
  • Check redirect lists. Allowed redirect addresses should list only your real domains.
  • Add rate limits where the platform offers them, especially on sign-in and on forms that send email.

For roles, keep it simple: a user, an admin, and nothing in between until you need it.

Check 4: Input and output

Anything a user types can be hostile. Three habits cover the basics.

  1. Validate on the server. Check length, type and allowed characters before saving.
  2. Never build database queries by joining strings. Use the database library's parameters. If the agent wrote string concatenation into a query, ask it to switch to parameters.
  3. Escape what you display. Text from users must not be inserted into a page as raw HTML. Most modern front-end frameworks escape by default, so be suspicious of code that turns that off.

Ask the agent to review its own code against exactly these three points. It is a good use of the model, since it can read the whole project quickly. Then spot-check the answer yourself. An agent's claim that "all inputs are validated" is a claim to test.

Check 5: Dependencies

Agents add packages freely. Each is code you now depend on.

npm audit
npm outdated

npm audit reports known problems in the packages you use. Read the high and critical items, and update where an update exists. Look through package.json for names you do not recognize, and remove packages the app does not use. For other languages, use the equivalent audit command of that ecosystem.

A particular trap: agents sometimes suggest a package name that does not exist or is a lookalike of a real one. Check that a package is the real one, from its official page, before installing anything you do not know.

Check 6: Backups and recovery

Security includes surviving your own mistakes. A tool or an agent can delete data.

  • Turn on automatic backups for the database, if the provider offers them.
  • Export a copy on a schedule that suits how often data changes.
  • Practice one restore. A backup you have never restored is a hope.
  • Keep production data away from where the agent works. The Wikipedia article records a July 2025 report from SaaStr's founder of a Replit agent deleting a database despite instructions not to make changes. We have not verified that report, and tools change their safeguards, but the lesson stands: separate production from the place an agent can act.

Using hooks and rules to keep an agent safe

If you use a terminal agent such as Claude Code to build the app, you can turn some of this into configuration. A deny rule keeps secrets out of reach in every permission mode, and a hook can refuse edits to protected files with a message the agent can read.

#!/bin/bash
# .claude/hooks/protect-secrets.sh  (PreToolUse on Edit|Write)
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
case "$FILE_PATH" in
  *.env|*.env.*|*/.git/*)
    echo "Blocked: $FILE_PATH is protected" >&2
    exit 2 ;;
esac
exit 0

See our hooks guide for how to register it. Rules that must hold belong in hooks and permissions, because the Claude Code docs describe CLAUDE.md as context rather than enforced configuration.

Prompts that help, and their limits

You can use the agent as a first-pass reviewer. Ask narrow questions, because broad ones get vague answers.

  • "List every place this app reads or writes the database, and say which user's data each call can reach."
  • "Find every secret, key or token in this repository, including config files, and say where each is used."
  • "For each route or function that changes data, say how it checks the caller is allowed to do it."
  • "List every package in package.json and say what it is used for. Flag any you cannot justify."

Read the answers as leads, not as proof. A model can miss a problem or describe code it did not fully read. The test with two accounts remains the evidence. If the agent's answer and your test disagree, believe the test.

What a first incident looks like

Even careful builders have one. Plan for it so you act calmly. Suppose you learn that a key leaked. The sequence is the same every time.

  1. Revoke the key at the provider. Do this first, before you clean anything up.
  2. Issue a new key and put it in the host's environment settings.
  3. Check the provider's logs for use you do not recognize, between the leak and the revoke.
  4. Remove the key from the code and history, and add a check so it cannot return.
  5. Tell the people affected if their data could have been reached. Rules may require this, and honesty builds trust.
  6. Write down what happened and what changed. Add the missing check to your routine.

A rehearsed response takes minutes, while an improvised one takes days. Print the six lines and keep them near the project notes.

Privacy basics for small apps

If you collect names, emails or anything else about people, a few basics apply whatever the stack. Collect only what the app needs. Say what you collect and why, in plain words, on a page users can find. Let people delete their account and data. Keep personal data out of logs, and out of prompts you send to an AI tool when you are debugging. Where law applies to you, such as rules on personal data in your users' regions, get advice from someone qualified, because these rules differ by place and a prompt cannot read them for you.

A pre-launch routine

Run this before every release. It takes under an hour for a small app.

Step

Time

Done when

Search code and history for secrets

10 min

No hits, or keys rotated

Confirm access rules on every table

10 min

Rules on, grants revoked where needed

Two-account test

15 min

Bob sees nothing of Alice's

Admin page as a normal user

5 min

Refused

Dependency audit

5 min

No unaddressed high issues

Restore test, once

15 min

A copy restored and opened

Keep a copy of the results in the repository. When something goes wrong later, that record shows what you checked.

When to get a reviewer

You have done the checks. Still, bring in a person who can read code if any of these is true: the app handles money, it stores personal or sensitive information, many people will use it, or you could not explain what a given part of the code does. A review for a small app can take a few hours, and finding one flaw pays for it. Deploying is covered separately in how to deploy a vibe coded app.

Our take

The disappointing truth is that most serious problems in AI-built apps are not clever attacks. They are open doors: a key in front-end code, a table with no rules, an admin page that trusts the screen. All three are found by the checks above in an hour.

So the best investment is not a tool. It is the habit of testing as a second user before you share the link. Add the two-account test to your launch routine and do it every time.

Checklist

  • Searched code and Git history for secrets, rotated any found
  • .env is ignored and no secret is in front-end code
  • Row level security on, with policies, on every exposed table
  • Two-account test passed for read, edit and delete
  • Admin pages refuse a normal user
  • Input validated on the server, queries parameterized
  • npm audit reviewed, unknown packages removed
  • Backups on, one restore tested
  • A reviewer has seen any code touching money or personal data

Related pages

Questions

How do I secure a vibe coded app?

Check six things before launch: no secrets in code or history, access rules on every database table, sign-in and permissions tested with a second account, input handled safely, dependencies updated, and backups with a tested restore.

What is the most common vibe coding security mistake?

A database with no access rules. Supabase's docs say a table in an exposed schema without row level security is readable and writable by any role with a grant on it.

Can the AI check its own code for security?

It can help find problems and explain them, which is worth doing. It cannot prove the app is safe. Test with a second account and have a person review anything handling money or personal data.

Is a security scanner enough?

No. Scanners find known patterns such as leaked keys and old packages. They do not know who should be allowed to see which record. That check you do by hand.

Loading poll...

Sources

  1. supabase.com/docs/guides/database/postgres/row-level-security
  2. en.wikipedia.org/wiki/Vibe_coding
  3. code.claude.com/docs/en/best-practices
  4. code.claude.com/docs/en/hooks-guide

Part of the Wbcom Designs family

The all-in-one WordPress community stack

Also ours: wbcomdesigns.comvapvarun.combrndle.com