Security by stack

Security for AI-built apps

Vibe-coded apps ship in hours, but the security basics —exposed secrets, missing database rules, open CORS, absent headers— get skipped along the way. This guide explains, without jargon, the flaws that actually bite AI-built apps, why they keep happening, how to check for them yourself in ten minutes or with a scanner in 30 seconds, and what to keep an eye on after launch.

What "vibe coding security" means

AI tools (Lovable, Bolt, v0, Cursor, Replit, Windsurf) generate apps with a very specific architecture: the browser talks directly to the database (Supabase, Firebase) and to external services (Stripe, OpenAI, Resend). There is almost no server of your own in between. That speeds everything up, but it moves security from your code to your configuration: what protects you are the database rules, the HTTP headers, the CORS policy and which keys live where, not how clean the interface code is.

Those pieces are not set up correctly by default, and the AI rarely configures them unless you ask. Its goal is for the app to work in the demo, and an unrestricted table or a key pasted into the frontend "work" perfectly. The result is apps that look flawless and expose data or keys to anyone who knows where to look: you do not need to be a hacker, opening the browser's developer tools is enough.

So "vibe coding security" does not mean learning cryptography or hiring an audit. It means knowing the half-dozen flaws that repeat in almost every AI-built app, knowing how to check them from the outside, and asking the same AI to fix them with precise instructions.

Why AI-built apps fail in the same ways

There is a pattern. The AI optimises for the code to compile and the screen to show data, not for a stranger to be unable to see it. When a query fails because of permissions, the shortest fix is to remove the permission that gets in the way: disable Row Level Security, add a rule that allows everything, or use the admin key. And the AI picks the shortest fix.

The second reason is that it copies templates. Variables prefixed with NEXT_PUBLIC_, VITE_ or NUXT_PUBLIC_ are sent to the browser by design, and many examples on the internet put keys there that should never leave the server. Firebase rules in test mode let anyone read and write for 30 days, and apps get launched with that mode still on. Security headers show up in almost no tutorial, so they do not show up in the app either.

The third is that nobody draws the threat model. Whoever builds with AI thinks about the user they want, not about the visitor who opens the Network tab, copies the API URL and removes the filter. This guide is about standing in that visitor's shoes for ten minutes.

The seven flaws that bite AI-built apps most

API keys in the browser. When you "connect" a service, the key ends up in client JavaScript, where it is public forever: anyone can read it by viewing the source and use it at your expense (OpenAI bills, emails sent from your domain, access to your data). The only keys that may go to the client are the ones designed for it, such as Supabase's anon or publishable key, Stripe's publishable key or the Firebase config, and only if the rules behind them are right.

Missing or weak database rules. Without Row Level Security enabled on every Supabase table, or with a policy that allows everything, anyone reads and writes your data without logging in, through the same API your app uses. In Firebase, rules in test mode or with allow read, write: if true do the same. It is the most serious and the most frequent flaw, and it was the origin of CVE-2025-48757, the vulnerability that exposed user data in apps built with Lovable.

Permissive CORS. An API that answers with Access-Control-Allow-Origin reflecting any origin and also allows credentials lets a malicious site make requests on behalf of your users and read the responses. The wildcard on a public API with no cookies is acceptable; reflecting the origin with credentials, never.

Missing security headers. Without Content-Security-Policy, Strict-Transport-Security, X-Frame-Options (or frame-ancestors), X-Content-Type-Options, Referrer-Policy and Permissions-Policy, your app is open to clickjacking, script injection, downgrade to HTTP and leaks of internal URLs. They are configured on the server or the host (Vercel, Netlify, Cloudflare) in ten lines.

Accessible sensitive files. A .env published by mistake, an exposed .git directory, source maps that let anyone rebuild the full source code, database backups or admin panels with no authentication. They are easy to find because attackers look for them automatically on every new domain that appears.

Misconfigured sessions and cookies. Session cookies without the Secure, HttpOnly and SameSite attributes, tokens stored in localStorage within reach of any script, or sessions that never expire. A small XSS turns into account takeover when the cookie is readable from JavaScript.

Endpoints that trust the client. API routes that accept the user id, the price or the role from the request body without checking it on the server. If the interface hides the admin button but the route still answers anyone, the button protects nothing.

What to review for your stack

Lovable, Bolt or v0 with Supabase. Check that every table has RLS enabled and per-operation policies (select, insert, update, delete) based on auth.uid(); that the service_role key is not in any public variable; that private Storage buckets have policies; and that views and RPC functions do not bypass the policies. The Supabase dashboard includes a Security Advisor that lists the worst offenders.

Cursor, Windsurf or Replit with Next.js, Nuxt or Express deployed on Vercel. Check which environment variables carry a public prefix, that API routes validate the session on every request and not just in the interface, that security headers are defined (vercel.json, next.config or nuxt.config) and that source maps are not published in production.

Firebase. Replace the test-mode rules with rules based on request.auth, in both Firestore and Storage; enable App Check so only your app can use your services; and make sure the Cloud Functions that do anything sensitive verify the user's token before acting.

The app "looking fine" does not mean it is safe

Hiding a button in the interface protects nothing: the request is still a public URL anyone can call directly from the browser console or with curl. Real security lives on the server and in the database, not in what the user sees. That is why checking from the outside —the way an attacker would— is the only way to know what is actually exposed.

Nor is a green HTTPS padlock enough. HTTPS encrypts the path between the browser and your server; it says nothing about whether the server hands data to people it should not. An app with a perfect certificate and a table without RLS is an app with a perfectly encrypted leak.

How to check it yourself in ten minutes

One: open your site and view the source (right-click, view page source). Search for key, secret, sk_, service_role and the names of the services you use. Anything that appears there is public.

Two: with the app open, go to the Network tab of the developer tools, find a request to your database or API, copy the URL and open it in an incognito window. If it returns data with no session, that endpoint is open. Logged in, remove the user filter from the URL: if it returns other people's rows, the policies are wrong.

Three: request your domain's headers with curl -I https://yourdomain.com and check whether Content-Security-Policy, Strict-Transport-Security and X-Frame-Options or frame-ancestors appear. If one is missing, it is not configured.

Four: try opening /.env, /.git/config, /config.json and any .js.map file from your bundle. All of them must return 404 or 403.

Five: create two test accounts and check that neither can see, edit or delete the other's data, uploaded files included. It is the most boring test and the one that finds the most flaws.

How to check it in 30 seconds

Scanaris automates those tests and a few more. It scans your published site read-only: it does not touch your code, inject anything or try to exploit anything; it looks at what is already public, the way anyone could from the outside. It checks headers, cookies, the TLS certificate, CORS, secrets in the JavaScript, sensitive files, technologies with known versions, your Supabase rules if you give it a read-only connection, and also how Google sees you and how AI reads you.

Every finding comes ranked by impact (critical first), explained in plain language and with a fix prompt ready to paste into Lovable, Cursor or whatever tool you use. Paste your URL, wait half a minute and you will know whether you can share your app with peace of mind.

What to watch after launch

Security is not a state, it is a habit. Every new table is born without RLS, every new function can put a key in the wrong place and every dependency ages. Schedule a periodic re-scan and review the differences, not the whole report: what matters is what has opened since last time.

Also watch what does not depend on the code: that the certificate and the domain do not expire, that the site responds, and that no scripts you did not put there show up in your users' browsers. And when you fix something, check it again from the outside: the fix counts when the scanner stops seeing it, not when the AI says it is done.

Scan my site free

Go deeper for your stack

Key security checks

Related guides

Frequently asked questions

Is my Lovable, Bolt or Cursor app secure?

It can be, but by default it usually ships with keys in the frontend, incomplete database rules and no security headers. The only way to know is to check your published site: Scanaris does it in 30 seconds, read-only.

Does having HTTPS mean my app is secure?

No. HTTPS encrypts the connection between the browser and your server, but it does not stop the server from handing data to people it should not. A table without RLS or a key in the frontend stay exposed with the padlock green.

Is scanning my site dangerous for it?

No. Scanaris runs read-only checks on already-public information (headers, cookies, certificates, accessible files). It never modifies, deletes or injects anything. You should only scan sites you own or are authorised to test.

How is this different from a pentest?

A pentest is days of manual work by specialists who try to exploit your app with authorisation. Scanaris is an automatic, read-only review that takes seconds and covers the configuration flaws that repeat across AI-built apps. It covers what fails most often; it does not replace a pentest if you handle very sensitive data.

Do I need to know security to use it?

No. Every finding comes with a clear explanation and a ready-to-paste AI fix prompt, so you can solve it without being an expert. Paste the prompt, review the change and scan again to confirm it is closed.

How often should I scan again?

Every time the AI touches the database or adds an integration, and at least weekly if the app is in production. Paid plans do it on their own and only notify you when something changes.