Vibe coders leak API keys to GitHub daily, then wake up to a $30k AI bill. The pre-merge check that catches sk- keys before they ship.

You merge a Cursor-generated PR on a Friday night. Tests pass. Vercel deploys. You ship and go to bed. Monday morning, your inbox has 47 emails from OpenAI saying you hit your spend limit, then your $2k card cap, then another card on file. Total damage: $38,000 burned across a weekend. A bot scraped your .env that got committed three commits back, the one you thought you removed. You did remove it from the latest commit. Git history kept it forever. This is the most common way solo founders get hit in 2026. Not SQL injection. Not some clever XSS chain. A live key in a commit, scraped by automation that watches the GitHub events firehose, turned into a model-prompting cash incinerator on your card. Vercel just shipped per-key budgets on AI Gateway, which is great. That is the airbag. This post is about not crashing the car.

02Your .env is not as removed as you think

The OPENAI_API_KEY you committed and removed is still sitting in your git history. Public repo, private repo, fork, archive, does not matter. Anyone who runs git log -p on a clone of your repo gets it. GitHub indexes it. Bots crawl it. Three places a vibe coder leaks keys without realizing. One: the first commit. You ran the Cursor agent, it generated an app, you ran git init and git add . before reading what was staged. .env went in. You noticed an hour later and removed it. The .env is still in the initial commit object forever, unless you rewrite history. Two: NEXT_PUBLIC_ prefixed vars. Cursor renamed your variable to NEXT_PUBLIC_OPENAI_KEY because client code needed it. That key is now baked into your client-side JavaScript bundle and visible in DevTools to anyone who opens your site. Vercel deploys it on every preview URL. Three: README examples. Bolt or Lovable wrote a setup guide using your actual key as the example value. README.md is in the repo. README.md is what GitHub shows first. Run this on your repo right now: git log --all --full-history -p | grep -E 'sk-[a-zA-Z0-9_-]{20,}|AKIA[0-9A-Z]{16}|ghp_[a-zA-Z0-9]{36}' If anything prints, those keys are live unless rotated. Rotate now, then read the next section.

03GitHub gets scraped in 14 seconds

Public research shows a key pushed to a public GitHub repo gets its first probe in under 60 seconds, often under 15. The pipeline is industrial: a bot subscribes to the public GitHub events stream, regex matches on key shapes like sk-proj-, sk-ant-, AKIA, ghp_, then immediately fires a test request to verify the key is live. If it works, it queues your key for monetization. What monetization looks like depends on the key. OpenAI keys run batch jobs against gpt-4o for resale, or power free wrapper sites that resell your quota. Anthropic keys go the same route on Claude. AWS access keys get used to spin up GPU instances for crypto mining, which is where the truly painful numbers come from. The recent GHSA-9pg3-25fq-p6cc advisory is one more reminder that automated scanners are getting faster every quarter. Vercel shipping budgets on AI Gateway keys is a real mitigation here. You can cap a specific key at $50 per day, get alerted at $30. That is the airbag, and it should be on for every AI key you create. But the airbag fires after the crash. The job is to not push the key in the first place. Add a per-key budget today on every gateway key you use, then move on to the pre-merge fix.

04The pre-merge check that actually stops this

You need a wall between your staged diff and your remote. The wall has three layers. Layer one: a pre-commit hook that scans staged changes for secret patterns before the commit lands. gitleaks protect --staged or trufflehog git --only-verified works. If a key matches, the commit is rejected. You unstage, fix, retry. Layer two: a GitHub Action on every PR that scans the diff against main. Same tools. Block merges on detection. This catches the case where a contributor disabled their local hook, or you ran git commit --no-verify because you were in a hurry. Layer three: scoped, budgeted keys. Stop using your personal OpenAI key for production. Create a project-scoped key per app. Set a Vercel AI Gateway budget. Same for Stripe restricted keys, and split your Supabase service role from anon. When a key leaks, the blast radius is one app, one budget, one rotation. Run this on the project you shipped this week: git log -p for known key prefixes and rotate anything that prints, confirm .gitignore contains .env and .env.local, check every NEXT_PUBLIC_ var is not a real API key, and set a per-key budget on every AI provider you use. Guardian runs all of this against your repo and your deployed Vercel env vars before you merge. It flags which keys are exposed, which are still live, and which preview URLs leak them in client bundles. You find out before the bot does.

The Guardian Team
Security for apps built with AI.

Catch the sk- key before it ever hits your git history

Guardian scans your repo, full git history, and Vercel env vars for live API keys, then tells you which ones are exposed before you merge the PR.

Scan my app free
More articles