Vibe-Coded SecurityApplication Security

Scan Your Vibe-Coded App: The Security Guide AI Skips

AI ships your app in a weekend and skips the boring, invisible parts — the database rules, the leaked keys, the access checks. Here are the six holes it leaves behind, how attackers find them, and how to close every one.

Cystene Team · June 22, 2026

Wiz Research found that roughly one in five AI-built apps ships with a real security hole — most often a database anyone can read. The average breach now runs past $4.8 million, and the window between a flaw going public and being weaponized is down to hours. None of these holes break your app — the page loads, the demo works — which is exactly why they sit there until someone finds them. This guide walks the six that show up most in apps built with Bolt, Lovable, v0, Replit and Cursor: what each is, how an attacker finds it, the exact fix, and the Cystene scanner that catches it.

Why a security team is writing your vibe-coding guide

Every hole in this guide is one we built a scanner for — exposed Supabase tables, secrets in your bundle, broken access control, missing headers. Cystene is the security platform that finds them in your live app, from the outside and the inside. This guide is the field manual for what it checks.

Explore the platform

Reading the code is not testing the app

Today's coding models are good reviewers — point one at your repo and it catches unsanitized inputs and missing checks. That is static analysis, and it genuinely raises your baseline. But every model shares the same blind spot: it reads the source. It never logs in, never sends a real request, never sees how the deployed system behaves under an attacker's hands.

The running app is a different artifact than the code that produced it — shaped by config, headers, environment variables, and the database. The most common flaw in AI-built apps proves the point. The code looks perfect in review; the bug only appears in a live request:

GET /invoice/4912→ 200 OK · yours
GET /invoice/4913→ 200 OK · someone else's

No reviewer flags this — the code did exactly what it was written to do. Only a test that actually sends the second request finds it. That is dynamic testing, and it is the half an AI reviewer can never reach.

Why AI ships these holes

AI coding tools optimize for one thing: code that runs. Ask for an invoice page and you get a working invoice page. What you do not get is the part no prompt asks for — the row-level policy on the database, the header config on the deploy, the check that the invoice is actually yours. Those live outside the code the model writes, in config and access rules it never sees.

So the app works on the first try and ships with the security of a building that has doors but no locks. The six holes below are not exotic — they are the predictable blind spots of generating an app instead of hardening one.

The six holes AI-built apps ship with

Ordered by how much they hurt. Each is real, common, and quietly invisible until someone finds it — and each is tagged with the scanner that catches it.

Your database is wide open

Critical

OWASP A01 · Broken Access Control

Apps that talk to Supabase or Firebase from the browser ship the public anon key in their bundle. Without Row Level Security, that key reads — and writes — every row in every table. Wiz found this exact misconfiguration is the most common one in vibe-coded apps.

How they find it: They lift the project URL and anon key out of your JavaScript, then query the tables every starter ships — users, profiles, orders — and read whatever answers.The fix: Enable RLS on every table and add a deny-by-default policy: USING (auth.uid() = id).Cystene catches it with baas_scan

Secrets in your JavaScript bundle

Critical

OWASP A02 · Cryptographic Failures

Keys for OpenAI, Stripe, AWS or your own backend that end up in client-side code — or in published source maps — are readable by anyone. A leaked secret key is a blank cheque against your account, and the bills arrive within hours.

How they find it: They grep your served bundles and .map files for known key patterns. It is fully automated and takes seconds.The fix: Move every secret server-side, rotate anything that already shipped, and only ever expose publishable keys to the client.Cystene catches it with secret_scan

Auth that lives in the UI, not the server

High

OWASP A01 · Broken Access Control

Hiding an admin button is not access control. If the endpoint behind it answers without a valid session — or trusts an id straight from the request — the protection is theatre. This is the OWASP number-one risk, and it is invisible to a code review.

How they find it: They change one digit in a request — /invoice/4912 becomes /invoice/4913 — and read data that is not theirs.The fix: Verify the session and the object owner on the server for every endpoint, never just in the front end.Cystene catches it with web_scan + api_scan

Private files left public

High

OWASP A05 · Security Misconfiguration

A committed .env, an exposed .git directory, a stray backup, or a live debug endpoint hands attackers your config and credentials directly. Generated apps leave these behind constantly.

How they find it: They request the usual paths — /.env, /.git/config, /backup.zip — and read whatever the server returns.The fix: Block dotfiles and archives at the edge, and keep secrets out of the repository entirely.Cystene catches it with web_scan

Missing security headers

Medium

OWASP A05 · Security Misconfiguration

Content-Security-Policy, HSTS, and X-Frame-Options are a ten-minute fix most generated apps skip. They blunt cross-site scripting, protocol downgrades, and clickjacking — the cheapest hardening you can buy.

How they find it: They read your response headers. Their absence is the tell that nobody hardened the deploy.The fix: Set CSP, HSTS, X-Frame-Options and X-Content-Type-Options in your hosting config or middleware.Cystene catches it with web_scan

Weak or misconfigured TLS

Medium

OWASP A02 · Cryptographic Failures

An expired certificate, a deprecated cipher, or a missing HTTPS redirect quietly downgrades every visitor. It stays invisible until someone is on the same network as your user.

How they find it: They inspect your certificate chain and negotiated ciphers, then sit on the wire for the rest.The fix: Auto-renew certificates, force HTTPS, and disable legacy TLS versions and ciphers.Cystene catches it with ssl_scan

The two fixes worth doing first

Two of the six close the most common critical findings. Neither takes ten minutes. First, lock every table with a deny-by-default policy so the public key only ever returns the caller's own rows:

-- lock the table, then allow only the owner's rows
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
CREATE POLICY "owner reads own row"
ON users FOR ALL USING (auth.uid() = id);

Then set the headers most generated apps ship without. Four lines turn off the easiest attacks against your front end:

Content-Security-Policy: default-src 'self'
Strict-Transport-Security: max-age=63072000
X-Frame-Options: DENY
X-Content-Type-Options: nosniff

Both show up on every scan until they are in place — which is the point of running one.

What a Cystene scan actually does

You can verify all six by hand. Or you point Cystene at your live URL and it runs the attacker's playbook for you, safely — the difference between an AI that reviews your code and a scanner that tests your app:

  • From the outside (DAST) — ports, DNS, SSL/TLS, headers, exposed files, and the app-layer checks above, run against your real deployment.
  • From the inside (credentialed) — host, cloud, and domain audits using credentials you control, for the holes a URL scan can never see.
  • An audit-ready report — every finding with a severity, a CWE / OWASP / MITRE mapping, and a copy-paste fix. The data-minimizing checks prove a table is open without ever reading a row.

The free tier covers the external checks and needs no card. Ship fast — just do not ship blind.

Find your six before an attacker does

Point Cystene at your live app and get all six checks — plus internal, credentialed audits — in a single scan, each with a fix you can paste straight in.

Scan my app free