ShipWatchFree scan

The vibe coding security checklist

You don't need to become a security engineer to ship safely. You need to check a short list of things that AI-built apps commonly get wrong, every time you ship.

This checklist is ordered by impact. The first few items are the ones that turn into "someone downloaded our whole user table" stories; the later ones are hardening. Each item has a quick way to check and a prompt you can paste into your AI tool. The general categories line up with long-standing guidance like the OWASP Top 10; this is the practical version for apps you built by prompting.

Secrets and keys

1. No secret keys in the frontend

Check: in your live site's developer tools, search all sources for sk_live_, sk-, AKIA, sb_secret_ and service_role. Anything prefixed VITE_ or NEXT_PUBLIC_ is public by design. Details and fixes.

Find every secret API key used in frontend code and move the calls that use it to server-side functions. Secrets must be server-only environment variables with no VITE_ or NEXT_PUBLIC_ prefix. List the keys so I can rotate them.

2. Supabase service_role key is server-only

Check: decode any eyJ... Supabase key in your bundle; "role":"service_role" means a full-access key is public. How to check and rotate.

3. Leaked keys have been rotated

Check: for every key that was ever in frontend code or git history, confirm a new key was created and the old one revoked. Deleting it from code doesn't revoke it.

Your database

4. Row Level Security on every table

Check: run select tablename, rowsecurity from pg_tables where schemaname='public'; in Supabase. Every row should be true. Missing RLS in Lovable-built apps was the subject of CVE-2025-48757 (researchers' write-up).

5. Policies are tight, not just present

Check: no using (true) on private data, every insert and update has a with check, and a logged-out curl to your REST endpoint returns nothing private. Step-by-step RLS test.

Enable RLS on all tables and write one policy per operation using "to authenticated" and "(select auth.uid()) = user_id", with WITH CHECK on inserts and updates. Never use "using (true)" on user data. Show me the SQL first.

6. Users can't edit their own role, plan or payment status

Check: as a normal user, try updating your own role, is_admin, credits or payment_status via the API. It should fail.

Make role, admin, plan, credits and payment status columns impossible for users to change directly. Only update them from a server-side function, and for payments only after verifying the Stripe webhook signature.

Files that shouldn't be public

7. No public .env file

Check: curl -s https://yourapp.com/.env. Many hosts return your homepage for unknown paths, so look at the content: KEY=value lines are a problem.

8. No public .git folder

Check: curl -s https://yourapp.com/.git/HEAD. If you see ref: refs/heads/..., your source code and its history may be downloadable.

Make sure my deploy only publishes the build output folder (like dist or .next), never the project root. Block requests to /.env, /.git and any other dotfile at the host level. Add .env* to .gitignore.

Transport and browser protections

9. HTTP redirects to HTTPS

Check: curl -sI http://yourapp.com should return a 301 or 308 with a location: https://... header.

10. HSTS is set

Check: curl -sI https://yourapp.com | grep -i strict-transport. MDN explains HSTS: it tells browsers to always use HTTPS for your site.

11. Content-Security-Policy, X-Frame-Options and nosniff

Check: the same curl -sI output should include content-security-policy, x-frame-options (or CSP frame-ancestors) and x-content-type-options: nosniff. A CSP limits the damage of injected scripts; frame protection blocks clickjacking. The OWASP Secure Headers Project has recommended values.

Add these response headers to every page for my host: Strict-Transport-Security: max-age=31536000; includeSubDomains, X-Content-Type-Options: nosniff, X-Frame-Options: DENY, and a Content-Security-Policy that starts from default-src 'self' and allows only the domains my app actually uses (list them for me). Also force a 301 redirect from HTTP to HTTPS.

Logic

12. Every permission check also exists on the server

Check: anything your UI hides (admin pages, paid features, other users' data) should still be blocked if someone calls the API directly. If the only thing stopping them is a hidden button, it isn't stopped.

List every permission or paywall check that currently happens only in the frontend. For each one, add an equivalent server-side check (RLS policy or server function) and tell me how to test it with a direct API request.

Run it every time you ship

AI tools change a lot of code per prompt, and a fix in one place can quietly undo another. Treat this list like a pre-flight check: quick, boring and done every time. The free ShipWatch scan covers items 1, 2, 7, 8, 9, 10 and 11 automatically against your live URL. Items 3–6 and 12 need you (or your AI) to look at the database and code, using the prompts above.

Scan your app free in 30 seconds

Paste your live URL. ShipWatch checks your page and JavaScript for leaked keys (including Supabase service_role), exposed .env and .git, missing security headers and HTTPS redirects, and gives you a plain-English report with fix prompts. Passive and read-only, no signup.

Run the free scan