VibeSecurity

Tools and workflow

Vibe Coding Security Checklist a Solo Founder Can Finish

Most security checklists fail for one reason: they are written for a security team, not for one person with a launch date. This vibe coding security checklist is written for the founder who built the app with an AI tool, does not read every line of it, and has one afternoon. Every item is something you can test on your own app, and every item has a pass condition, so you know when you are done.

By the VibeSecurity team7 min read

How to use this checklist

Run the checks in order, and only against your own app and your own accounts. The order matters: secrets and data access come first because a failure there is usually silent and total, while a missing header is loud only to a scanner.

A check is done when you have seen the pass condition with your own eyes. 'The AI said it added row security' is not a pass. A logged-out request that returns nothing is.

Do not try to be perfect. The aim is to close the failures that let a stranger read or change your users' data without any special skill. Everything else can be scheduled.

Group 1: Secrets and keys

AI tools copy keys into files because it makes the demo work. The fix is cheap if you catch it now and expensive after a key has been used by someone else.

  1. 1Search your repository and its history for keys. Run a secret scanner such as gitleaks over the full git history, not just the current files. Pass: zero findings, or every finding has been rotated and removed from use.
  2. 2Check what ships to the browser. Open your deployed site, view the built JavaScript in developer tools, and search for the names of your service keys. Pass: only keys that are designed to be public, such as a database public key, appear.
  3. 3Confirm that .env files are ignored by git. Run git check-ignore .env. Pass: the file path is printed back.
  4. 4Confirm that production and development use different keys. Pass: revoking the development key would not break production.
  5. 5Rotate anything that has ever been pasted into a chat, an issue or a screenshot. Pass: the old value no longer works when you try it against your own service.

Group 2: Data access

If your app talks to a hosted database straight from the browser, the database rules are your real backend. This is the group that decides whether a stranger can read your users' rows.

  1. 1Turn on row-level access rules for every table the browser can reach. Pass: your provider's dashboard or a SQL query shows the rules enabled on every such table.
  2. 2Test as a logged-out visitor. Use a private window, and the public key from your own front end, to request each table. Pass: you get an empty result or a permission error.
  3. 3Test as user A against user B. Create two test accounts and try to fetch B's record by ID while signed in as A. Pass: the request is refused or returns nothing.
  4. 4Test writes, not just reads. Try to update or delete another test user's row. Pass: refused.
  5. 5Check file storage. Open a file URL from a private bucket in a logged-out window. Pass: it does not load without a signed link.

Group 3: Authentication and sessions

  1. 1Try to reach a protected page while logged out. Pass: you are redirected, and no protected data flashes before the redirect.
  2. 2Call your API directly, with no cookie or token. Pass: a 401 or 403, never data.
  3. 3Check that admin actions are enforced on the server. Log in as a normal user and replay an admin request using your browser's network tab. Pass: refused.
  4. 4Try a password reset for an email that does not exist. Pass: the response looks identical to a real one, so accounts cannot be enumerated.
  5. 5Confirm that sessions end. Log out, then replay a request with the old token. Pass: refused.

Group 4: The edges of your app

These checks are quick and catch a surprising number of leftovers from the prototype stage.

  1. 1Look for debug routes and test pages. Search your routes for names like debug, test, seed and admin. Pass: none reachable in production.
  2. 2Read your error pages. Trigger a failed request. Pass: no stack traces, file paths or SQL in the response.
  3. 3Check response headers with a header checker or your browser's network tab. Pass: HTTPS enforced and a Content-Security-Policy present, even if it starts in report-only mode.
  4. 4Rate limit sign-in and any endpoint that sends email or SMS. Pass: the sixtieth rapid request from your own script is slowed or refused.
  5. 5Check third-party scripts. List every script your pages load. Pass: you can name the reason for each.

Group 5: Recovery

  1. 1Confirm backups exist and know how far back they go. Pass: you can state the restore window without looking it up.
  2. 2Restore one backup into a scratch project once. Pass: it works, and you know how long it took.
  3. 3Write down the three steps you take if a key leaks: revoke, rotate, check logs. Pass: the steps are in a file, not in your head.

The whole checklist on one page

Print this table or paste it into your tracker. Each row is one test you can run today.

Check, how to test on your own app, pass condition
CheckHow to test on your own appPass condition
No secrets in git historyRun a secret scanner over the full historyZero live findings
No service keys in the browser bundleSearch built JavaScript for key namesOnly public-by-design keys found
Row rules on every exposed tableQuery as a logged-out visitor with the public keyEmpty result or permission error
Users cannot read each other's dataFetch user B's record while signed in as user ARefused or empty
Server enforces rolesReplay an admin request as a normal user403
API rejects anonymous callsCall the endpoint with no token401 or 403
Private files stay privateOpen a private file URL logged outDoes not load
No leaky errorsTrigger a failure and read the responseNo stack trace or SQL
Abuse limits existScript rapid sign-in attempts against yourselfSlowed or refused
Restore worksRestore a backup into a scratch projectData present, time noted

What to do when a check fails

Fix in this order: anything that exposes data, then anything that lets a stranger act as someone else, then everything else. Do not ask the AI tool to 'make it secure'. Give it the specific failed test, for example 'requests from a logged-out user to the orders table return rows, add a policy so users only read rows where user_id matches their own ID', then run the same test again.

Keep the tests. A failing check you turn into a repeatable script becomes a regression test, which matters because the next AI-assisted change can quietly undo a fix.

Frequently asked questions

How long does a vibe coding security check take?

For a small app with one database and a few dozen routes, most of the checks above take one focused afternoon. The data access group takes longest because you need two test accounts. Once you have scripted the tests, rerunning them before each release takes minutes.

Can I ask the AI tool to run this checklist for me?

It can help write the tests and fix what fails, but it should not be the judge of its own work. Run the pass conditions yourself against the deployed app. A tool that wrote a flawed policy will often describe it as correct.

Which check matters most?

The logged-out data access test. If a stranger with your public key can read or write your tables, every other control is moot. It is fast, needs no special tools, and catches the most damaging class of failure in apps built on hosted databases.

Do I need a penetration test before launch?

Not for a first small launch, provided you finish a checklist like this one. A professional review becomes worth paying for once you store sensitive personal, health or payment data, or when a customer's procurement team asks for one.

Put it into practice

Sources

  1. 1.NVD: CVE-2025-48757
  2. 2.Supabase docs: Row Level Security
  3. 3.OWASP Secrets Management Cheat Sheet
  4. 4.Gitleaks project on GitHub
  5. 5.MDN: Content Security Policy