Your AI Shipped the App. Did It Leave the Keys in the Repo?
Last month, security firm UpGuard told TechCrunch it had found around 16,000 Supabase-hosted databases exposing personal data — names, addresses, phone numbers, even passwords — queryable by anyone on the open web. Not hacked. Just... left open.
The mechanism behind almost all of it: AI coding tools write SQL migrations directly, and in that path Postgres row-level security defaults to off. Supabase's dashboard turns RLS on when you click through the Table Editor, but AI tools don't click through dashboards. A founder types a prompt, the AI ships a working app in an afternoon, and nobody ever flips the switch that keeps one user from reading every other user's rows.
That is the vibe-coding security gap in one sentence: the app works, so nobody checks the configuration.
What I built
vibe-shipcheck — a zero-dependency Python CLI that runs the pre-publish security checklist vibe-coded apps never get:
pip install vibe-shipcheck
vibe-shipcheck ./my-app
vibe-shipcheck 0.1.0 — pre-publish security check
Scanning: /home/hao/my-app
ERRORS:
[env-committed] .env — .env file is tracked by git — its secrets ship with the repo
fix: Add it to .gitignore, run `git rm --cached .env`, rotate every key it held.
[rls-disabled] supabase/migrations/001_init.sql — migration creates table(s) profiles without ENABLE ROW LEVEL SECURITY — readable by anyone with the anon key
fix: Add `ALTER TABLE <table> ENABLE ROW LEVEL SECURITY;` plus policies for every table, or enable RLS in the dashboard.
WARNINGS:
[supabase-url-exposed] src/lib/supabase.ts:3 — Supabase project URL in source
fix: The URL itself is public, but anyone with it + your anon key can query every table whose RLS is off.
[cors-wildcard] api/main.py:12 — wildcard CORS origin — any website can call this API
fix: Restrict origins to your own domains before publishing.
2 error(s), 2 warning(s)
BLOCKED — fix the errors above before publishing.
What it checks:
-
Committed
.envfiles — tracked by git, untracked-but-unignored, or unverifiable. The classicgit add .leak. -
Hardcoded secrets — AWS, GitHub, Stripe, OpenAI-style keys, PEM blocks, plus generic
password=/api_key=literals. Proper env references (os.environ[...],process.env...) and placeholders are never flagged. -
Supabase exposure — project URLs in source, and it actually decodes JWTs to tell the public
anonkey fromservice_role(which bypasses all RLS and must never be in code). -
Missing RLS — scans your migration SQL; any
CREATE TABLEwithoutENABLE ROW LEVEL SECURITYis an error. This is the exact UpGuard failure mode. - Wildcard CORS and debug/dev flags left on.
Every finding ships with a one-sentence fix line — the audience is someone who prompted an app into existence, not someone who reads CVE feeds.
Exit code 1 on errors, so it drops straight into CI or a deploy script. --strict fails on warnings too, --json gives machine-readable output.
Why not just use Trivy / Gitleaks?
Those tools scan for vulnerabilities in code — CVEs, secret patterns in history. That's a different moment. vibe-shipcheck owns the pre-publish checklist: the ten seconds between "the AI says it's done" and "it's live on the internet." Nobody hand-writing an app forgets RLS on every table; AI tools do it by default. The failure mode is configuration, not code, and it needs a checker that thinks in terms of shipping, not CVEs.
Use both: Gitleaks in CI for deep secret history, vibe-shipcheck as the gate right before you hit publish.
Try it
- GitHub: https://github.com/hahahahahahahahah6/vibe-shipcheck
- PyPI: https://pypi.org/project/vibe-shipcheck/
pip install vibe-shipcheck and run it against your own vibe-coded projects — I'd genuinely like to hear what it finds. If it catches a real leak before you ship, tell me in the comments.
tags: python, security, supabase, vibecoding
canonical: https://github.com/hahahahahahahahah6/vibe-shipcheck
Top comments (0)