glimfly
guide updated

How do you know if your vibe-coded app is secure?

The short answer

Your app is secure enough to launch once you’ve personally checked four things, not once it “feels done” because the demo works. No API key sitting in your frontend code or client-side JavaScript. Row Level Security actually turned on, with a real policy, on every database table that touches user data. Every form field and URL parameter treated as attacker input until your agent proves otherwise. Dependencies that get updated instead of quietly ignored. None of that needs a computer science degree. It needs about ten focused minutes and knowing exactly where to look. The two most-cited security failures of the vibe coding era (a vulnerability across 170+ apps and a database exposing 1.5 million tokens) both came from skipping the second item on that list, not from some sophisticated attack nobody could have predicted.

The four things that get vibe-coded apps hacked

Exposed API keys. When an agent wires up a third-party service, the fastest way to make the demo work right now is to paste the key straight into the code that calls it. If that code runs in the browser, anyone can open dev tools, check the Network tab, and read it. This is reportedly the single most common security complaint in vibe coding communities. The fix is a real environment variable instead of a string in a component, plus knowing the difference between a key, a secret, and a token, since that’s what decides which ones are ever safe to expose at all.

A database with no real access control. Supabase and similar platforms hand your frontend a public key by design. That part is normal. What makes a project unsafe is a table that key can reach with Row Level Security either off, or on with a policy that amounts to “allow everyone.” Supabase’s own documentation is direct about this: once RLS is enabled, no data is returned through the API “until you create policies,” and the docs state RLS “must always be enabled on any tables stored in an exposed schema.” Agents tend to generate the working CRUD screen first and the access policy never, because the demo runs fine either way, right up until a stranger finds it.

Input nobody double-checked. A search box, a signup form, a URL parameter, anything a visitor types or edits becomes a place an attacker can try to sneak in something other than data. Untreated, that path leads to SQL injection. If your app also feeds outside text (uploaded files, scraped pages, incoming emails) into an AI feature, the same idea shows up as prompt injection: instructions hidden in content your agent reads and treats as a command instead of just data to summarize.

Dependencies nobody revisits. Every package your agent installs to get a feature working stays in your project after that feature ships, and a known flaw in one of them becomes your flaw too. Most vibe-coded projects never run an update pass because nothing forces the question.

Two real incidents worth knowing

CVE-2025-48757 (Lovable, 2025). A security researcher found that a large batch of apps built on the Lovable platform had misaligned Row Level Security between what the interface checked and what the database actually enforced. The published analysis covered 303 insecure endpoints across 170 sites, about one in ten of the projects examined, and it’s now tracked as a critical-severity CVE. The cause wasn’t exotic: a query built to expose “your” data quietly returned everyone’s, because no policy stopped it.

Moltbook (January 2026). Researchers at security firm Wiz found a misconfigured Supabase database sitting open with no Row Level Security behind Moltbook, an AI-agent social network. It exposed roughly 1.5 million API authentication tokens, tens of thousands of user emails, and thousands of private messages, some containing third-party credentials. The team fixed it within hours of being told. It’s the same root cause as the Lovable case, in a different app, eight months later.

The checklist you can run today

  1. Open your browser’s dev tools, reload the app, and scan the Network and Sources tabs for any string that looks like a real key (sk-, AIza, a long random token). If you find one, rotate it at the provider immediately and move it into an environment variable.
  2. In your database dashboard, open every table that stores user data and confirm RLS is on with a policy that actually restricts rows, not just enabled with no policy or a policy of “true.”
  3. Ask your agent, plainly, whether each query touching a form or search field is parameterized or built by joining strings together. The second answer means SQL injection risk.
  4. Check that .env is listed in your .gitignore, then confirm it was never committed before that rule existed. If it was, the keys inside are burned regardless. Rotate them.
  5. Run your dependency updater (npm audit or ask your agent to) and update anything flagged, especially packages touching auth or the database.
  6. If the app reads content you don’t control into an AI feature, ask what happens if that content contains an instruction instead of information.

What “secure enough” looks like at each stage

A portfolio site with no login needs less scrutiny than a tool that stores payment details, and treating both the same wastes effort you could spend elsewhere. A rough order of what raises the stakes: an email address is a minor leak, a password or private message is a real one, and payment or health data means you’re now handling something regulators and your users both expect you to protect properly. If you’re in that last group, a professional security review before launch is proportional to what you’re holding, not overkill. For everything smaller, the checklist above, run honestly, covers the failure modes that show up in public incidents.

What Glim would tell you

Glimfly is building Glim, a firefly that sits next to your coding agent and narrates what it’s actually doing while it does it, not after you find out from a Reddit thread. Glim is built to flag the moment an agent writes a key into a component instead of an environment variable, or generates a table with no Row Level Security policy attached, so you catch it before it ships instead of after. Look up any term above in the dictionary whenever the explanation moves faster than your agent.

People also ask

“What security mistakes show up most in vibe-coded apps?”

The two that dominate real incidents are API keys sitting exposed in frontend code, and a database left open because Row Level Security was never turned on. CVE-2025-48757 found that RLS gap across 170+ apps built on one AI app builder, and a January 2026 incident exposed 1.5 million API tokens from an AI social network for the same reason. Both were fixable in minutes once someone checked for them.

“Do I need to hire a security professional before I launch?”

Not for a portfolio site or an internal tool with no real user accounts. The checklist below covers that case well. If you're handling payments, health information, or anything you'd hate to see leaked, like passwords or private messages, get a professional review before launch. That review costs far less than the breach it prevents.

“Can Claude Code or Cursor introduce a security bug without me asking for one?”

Yes. An agent optimizing to get the demo working will often take the fastest path, which sometimes means putting a key directly in a component or leaving a database policy wide open so a query doesn't fail on the first try. That's the same shortcut a rushed developer might take under deadline, not malice. It's exactly why checking these specific spots yourself matters more than trusting that the app runs.

Words from this guide

Want this explained about your own project?

Glim watches your coding agent work and explains your sessions in plain words, live. Join the waitlist to get it first.