Shipping AI-built apps with confidence
Security, release readiness, and shipping AI-built apps with confidence. Field notes from the team building VibeZero.
55 posts
Your passwordless login is protected by a password
Magic link security explained: why the random token is the easy half, and how leaked links, email scanners and pre-hijacked accounts take over accounts anyway.
Read postMore field notes
- 24 min readsecurity
A perfectly random token that stopped nothing
The OAuth state parameter only stops login CSRF when it is bound to the browser that started the flow. Six real CVEs where the value was random anyway.
Read post - 19 min readsecurity
One string comparison decides who gets the login
The redirect URI is where your login credential gets delivered. Loose matching hands it to an attacker. Why exact matching is the rule, with real bypasses.
Read post - 21 min readsecurity
The second factor was on. Nobody had to break it.
MFA bypass rarely breaks the second factor. It uses a second login path, an unchecked aal claim, a guessable code, or the reset flow. Five shapes, with fixes.
Read post - 20 min readsecurity
Bcrypt was correct. Eleven million passwords came out anyway.
Password hashing failures explained: the Ashley Madison column that undid bcrypt, the 72 bytes that let Okta skip a password, and the parameters to set.
Read post - 16 min readsecurity
Nobody guessed the password. Somebody else already lost it.
Credential stuffing logs in with real passwords leaked from other sites, so every attempt succeeds. The 23andMe case, why IP rate limits miss it, and the fixes.
Read post - 17 min readsecurity
The attacker does not want your session. They want you to use theirs.
Session fixation is account takeover in reverse: the attacker supplies the session before you log in. How it works, the 2026 Ghost CVE, and the one-line fix.
Read post - 17 min readsecurity
Nobody stole the password, and the account was still gone
Session hijacking is account takeover with no password and no MFA prompt. How sessions leak, what Secure, HttpOnly and SameSite really buy, and how to kill one.
Read post - 15 min readsecurity
Your app asked the attacker where to send the reset link
Password reset poisoning lets an attacker choose the link in your reset email. How the Host header does it, and where the reset URL should come from instead.
Read post - 10 min readsecurity
The admin page nobody linked to is already public
Forced browsing is requesting a URL nobody linked you to. Why the admin route in your bundle is already public, and why middleware is the wrong place to guard.
Read post - 10 min readsecurity
Every customer's data is one missing predicate away
Multi-tenant data leakage is one customer reading another's rows. Why tenant scoping fails in queries, caches, and pooled connections, and how to enforce it.
Read post - 8 min readsecurity
Client-side env prefixes, explained
NEXT_PUBLIC_ and VITE_ are not naming conventions. They are instructions to your bundler to publish the value. What that means and how to check your build.
Read post - 8 min readsecurity
.env file exposure, explained
A .env file leaks two ways: committed to a repo, or served by your own web server. One extortion campaign harvested 90,000 variables from the second route.
Read post - 9 min readsecurity
Secrets in git history, explained
Deleting the commit does not delete the secret. Why git keeps every version forever, what GitHub keeps after a force push, and how to actually clean it up.
Read post - 9 min readsecurity
Hardcoded credentials, explained
A credential written into source code cannot be rotated, scoped, or revoked without a release. Why AI generators produce them by default and how to find yours.
Read post - 10 min readsecurity
JWT expiration, explained
The exp claim is optional, logging out does not invalidate a token, and a stolen JWT is valid until it expires. What to set, and what to check instead.
Read post - 11 min readsecurity
JWT alg=none, explained
The JWT header tells the verifier which algorithm to use, and the header is written by whoever sends the token. Why alg=none still ships, and the fix.
Read post - 10 min readsecurity
JWT weak secrets, explained
An HS256 token contains everything an attacker needs to test a billion guesses offline. Why signing secrets get cracked, published, or shipped as defaults.
Read post - 9 min readsecurity
CSRF, explained
SameSite cookies made CSRF rarer, not gone. The gaps the browsers left open, a 2025 SSO account takeover, and the three defenses worth having, in order.
Read post - 7 min readsecurity
DOM XSS, explained
The injection happens after your server is done, so no server-side fix touches it. Sources and sinks, the jQuery CVEs scanners keep flagging, and Trusted Types.
Read post - 8 min readsecurity
Reflected XSS, explained
The payload lives in the URL, not your database. How an APT used it against NATO webmail, why the browser stopped helping in 2019, and what actually works.
Read post - 9 min readsecurity
Service role key exposure, explained
The Supabase key that ignores every RLS policy you wrote, why AI builders keep putting it in the browser, and the exact order to fix it in when it leaks.
Read post - 8 min readsecurity
Stored XSS, explained
A payload saved once runs in every reader's browser. The MySpace worm, a Roundcube CVE exploited in the wild, and the sanitizer settings that actually stop it.
Read post - 8 min readsecurity
Account enumeration, explained
Three channels tell an attacker whether an email has an account: the body, the status code, and the clock. How to close all three without breaking signup.
Read post - 7 min readsecurity
Command injection, explained
A filename with a semicolon becomes a shell command running on your server. Why the array form is the real fix, and why argument injection survives it.
Read post - 7 min readsecurity
CORS misconfiguration, explained
Reflecting the Origin header with credentials turns any website into a client of your API. The four broken policies, and the allowlist that replaces them.
Read post - 7 min readsecurity
Default credentials, explained
Default passwords built a botnet that took down half the internet. Why they survive in AI-generated stacks, and the compose and seed patterns that fail closed.
Read post - 6 min readsecurity
DNS rebinding, explained
DNS rebinding turns a browser tab or a URL validator into a client on your private network. Why the same-origin policy misses it, and the two fixes that hold.
Read post - 6 min readsecurity
Mass assignment, explained
One extra JSON field turns a profile update into an admin promotion. The GitHub incident that named the bug, and the allowlist patterns that close it for good.
Read post - 7 min readsecurity
NoSQL injection, explained
No string concatenation, no quotes to escape, still injectable. How a JSON body becomes a MongoDB query operator, and the three lines of code that stop it.
Read post - 7 min readsecurity
Open redirect, explained
Your domain, your TLS certificate, the attacker's destination. The bypasses that defeat every string check, and the one comparison that actually works.
Read post - 8 min readsecurity
Privilege escalation, explained
The user_metadata field every generated Supabase app trusts is writable by the user. Why role checks belong in a table, and the policy pattern that holds.
Read post - 6 min readsecurity
Verbose error messages, explained
A stack trace in production hands an attacker your file paths, framework versions, and query shapes. What leaks, why it multiplies other bugs, and how to fix it.
Read post - 6 min readsecurity
API key exposure, explained
29 million secrets hit public GitHub in 2025, and 64 percent of the ones leaked in 2022 still work. Why a leaked key stays leaked, and the order to fix it in.
Read post - 6 min readsecurity
Broken access control, explained
OWASP ranks broken access control first, found in 94 percent of tested apps. Why it is the hardest class to scan for, and the one design that prevents it.
Read post - 8 min readsecurity
How to secure a Bolt.new app
Bolt.new puts your Supabase service role key behind a VITE_ prefix, which publishes it to the browser. Here are the five fixes, worst first, with code.
Read post - 6 min readsecurity
How to secure a Replit app
Replit apps fail in a predictable order: agent reach into production, split secret stores, missing authorization, open endpoints, stale deps. Fixes with code.
Read post - 6 min readsecurity
How to secure a v0 app
v0 blocks the NEXT_PUBLIC_ mistake and does not check who calls your Server Actions. Five fixes for a v0-generated Next.js app, worst first, with code.
Read post - 6 min readsecurity
IDOR, explained
Change an id in the URL, get someone else's record. Why AI-generated apps ship IDOR by default, what the one-line fix is, and how to test it in five minutes.
Read post - 5 min readsecurity
Is Bolt.new safe?
Yes, with one documented default that publishes your most powerful database credential to every visitor. Here is what to check in your own build, in order.
Read post - 5 min readsecurity
Is Lovable safe?
Yes, and one documented failure got 170+ Lovable apps breached. What CVE-2025-48757 showed, why the security scan missed it, and the checks that answer it.
Read post - 5 min readsecurity
Is Replit safe?
Safer than it was in July 2025, when the Agent deleted a live production database during a code freeze. What Replit changed, and what it still leaves to you.
Read post - 4 min readsecurity
Lovable security checklist
Ten checks for a Lovable app, each one runnable in under two minutes, in the order that matters. Copy the command, read the answer, decide if you can launch.
Read post - 6 min readsecurity
Lovable vs Bolt.new: security compared
Same database, same default-off row security, two different ways to leak a key. What each platform gets right, what each gets wrong, and which risk is yours.
Read post - 6 min readsecurity
Prompt injection, explained
Prompt injection has no input-sanitization fix, because instructions and data share one channel. What actually reduces the blast radius, with agent config examples.
Read post - 6 min readsecurity
RLS misconfiguration, explained
Row Level Security is the only thing between your public anon key and your data. How it fails, why a policy can exist and deny nothing, and how to test it.
Read post - 6 min readsecurity
SQL injection, explained
SQL injection is 27 years old and still in the OWASP Top 10. Why AI-generated code reintroduces it, the one fix that actually works, and how to test for it.
Read post - 6 min readsecurity
SSRF, explained
Server-side request forgery turns your backend into the attacker's proxy. Why blocklists fail, what DNS rebinding defeats, and the validation order that works.
Read post - 5 min readsecurity
How to secure a Lovable app
Lovable ships four predictable security gaps: RLS left off, keys in the bundle, unchecked ownership, and stale deps. Here is the code that closes each one.
Read post - 4 min readsecurity
The fix your AI swears it shipped
Prompting the AI to fix its own security bugs feels like closure. Why unverified fixes fail, how they quietly regress, and what a real fix loop looks like.
Read post - 5 min readsecurity
72,000 photos and no lock on the door
The Tea app breach exposed 72,000 user photos, including 13,000 selfies and government IDs, in a cloud storage bucket with no authentication.
Read post - 4 min readsecurity
1.5 million keys and not one line of code
The Moltbook breach exposed 1.5 million API keys: a vibe-coded app shipped a Supabase backend with row-level security off. Why it keeps happening.
Read post - 1 min readannouncements
Introducing the VibeZero blog
Why we are writing about security, release readiness, and shipping AI-built apps without the guesswork.
Read post - 5 min readsecurity
The most common vulnerabilities in vibe-coded apps
What actually goes wrong when apps are built by prompting an AI: the five vulnerability classes that show up again and again, with the research behind each one.
Read post - 1 min readsecurity
The five layers of a release gate
A single scan should look at code, dependencies, secrets, configuration, and the running app. Here is why each layer matters.
Read post