Blog · ← All posts
Scan Your Lovable Code Before Deploying
Last updated: October 2026 · 8 min read
Lovable turns a sentence into a working app in minutes, a React/Vite frontend, usually backed by Supabase. That speed is the product. It is also the attack surface: the same model that writes your landing page in 90 seconds also writes your auth flow, your API calls, and your key management in 90 seconds, with no threat model in between.
This is a practical pre-deploy checklist for Lovable-generated code. Every item below maps to a check class Vibe-Code Audit actually runs, not theory, the exact detectors our scanner applies when you paste code in. Seven checks, each with the fix.
1. The Supabase service key in client code
The single most common Lovable failure. Lovable projects often end up with the service_role key, the key that bypasses every Row Level Security policy, sitting in the frontend bundle. Ask for "admin dashboard" and the model reaches for the key that makes it work.
// VULNERABLE — service_role key in client code const supabase = createClient(URL, "eyJhbGciOi...service_role..."); // FIXED — client uses the anon key + RLS; admin work moves server-side const supabase = createClient(URL, import.meta.env.VITE_SUPABASE_ANON_KEY); // privileged operations run in an edge function with the service key // stored in server-side env, never shipped to the browser
What our scanner does: the secrets check class (32 secret patterns on Pro, covering Supabase keys) flags key-shaped strings in pasted code and shows the blast radius, exactly which tables that key can read and write. Pro adds the rotation runbook.
2. dangerouslySetInnerHTML with user content
Ask Lovable to render rich text, Markdown, or "make this display HTML," and it reaches for dangerouslySetInnerHTML. The name is a warning the model ignored. If any part of that HTML comes from users, you have a stored XSS vector.
{/* VULNERABLE */}
{/* FIXED — sanitize first, render second */}
import DOMPurify from 'dompurify';
What our scanner does: the XSS check class flags untrusted values rendered into HTML. On Pro, taint tracking goes further: it proves data-flow from the request input to the sink, so the finding isn't "this might be XSS," it's "this input reaches this sink with no sanitizer in between."
3. Missing security headers
Lovable deploys to its own hosting; the generated app rarely sets a Content-Security-Policy or clickjacking protections. Headers won't fix your code, but they limit what an XSS can do, no inline scripts, no framing by attacker pages.
What our scanner does: the headers check class in our live-site audit grades your deployed app's security headers (CSP, X-Frame-Options, HSTS) and tells you exactly which are missing.
4. Exposed build artifacts
Lovable-style deploys sometimes ship sourcemaps or leave /.env reachable, files the bundler was never supposed to publish. A .env that 404s is fine; a .env that downloads is your database.
What our scanner does: the exposure check class probes the live site for /.env, /.git, and readable sourcemaps. The secrets-in-build-artifacts advanced detector (Pro) hunts key material baked into compiled bundles.
5. Hallucinated npm packages
AI builders invent package names. Ask for a niche integration and the model may import a library that doesn't exist, or worse, one that exists because a squatter registered the invented name. This is the slopsquatting problem: your npm install pulls attacker code into your build.
What our scanner does: SlopSquat Shield (Pro) verifies every import in your pasted code live against npm, hallucinated, newborn, and typosquat packages get flagged, with the real package the AI probably meant.
6. String-eval leftovers: eval, new Function, timer strings
Models occasionally generate eval(userInput), new Function(dynamicCode), or setTimeout(codeString, …) to "make it dynamic." All three are arbitrary code execution with extra steps.
// VULNERABLE
eval(`calculate(${userFormula})`);
setTimeout("refresh(" + userId + ")", 1000);
// FIXED — real functions, real arguments
calculate(parseFormula(userFormula));
setTimeout(() => refresh(userId), 1000);
What our scanner does: the eval usage, code injection, and setTimeout check classes flag every string-to-code sink in your paste.
7. RLS policies the model wrote for you
This one deserves its own section, because it's the Lovable-specific bug that bites hardest. Supabase Row Level Security is the only thing standing between your database and the internet, and Lovable generates the policies. The model's favorite shortcut is a policy that allows everything, written to make the feature work in the preview:
-- VULNERABLE — the model's favorite "make it work" policy CREATE POLICY "allow all" ON orders FOR ALL USING (true); -- FIXED — users see their own rows, nothing else CREATE POLICY "own orders" ON orders FOR SELECT USING (auth.uid() = user_id);
USING (true) means every visitor with the anon key can read every row. Combined with check 1 (the service key in client code), it's a pattern we see often enough to name: the wide-open database. The app works beautifully. So does anyone else's script.
Review every policy the model created. For each table, answer two questions: which rows should an anonymous visitor see (usually none), and which rows should a logged-in user see (usually their own). If a policy can't answer those questions, it shouldn't exist. And test as the attacker: create a second account, open the app, and try to read rows that belong to the first account. Five minutes, and it catches the USING (true) every time.
What our scanner does: paste your policy SQL or the generated migration files and the secrets and advanced patterns classes flag permissive RLS shapes alongside key exposure. The live-site audit can't read your policies, so this one is on you to paste in.
The pre-deploy checklist
- ☐ No
service_rolekey anywhere in client code, anon key + RLS only - ☐ No
dangerouslySetInnerHTMLwithout a sanitizer (DOMPurify) - ☐ CSP + X-Frame-Options headers present on the deployed URL
- ☐
/.envand/.gitreturn 404 on the live site - ☐ Every npm import resolves to a real, established package
- ☐ No
eval,new Function, or string arguments tosetTimeout
How the scan works
Paste your Lovable-generated code (or drop your deployed URL) into Vibe-Code Audit. The Free scan runs the secrets, code, XSS, and eval checks with a 0–100 score; Pro adds taint tracking, the 32-pattern secret scan with blast radius and rotation runbooks, the 16 advanced detector families, and SlopSquat Shield. One scan takes seconds, do it before every deploy, not after the breach report.
FAQ
Can I scan code before I deploy, or only the live URL?
Both. Paste code directly for pre-deploy review, or enter the deployed URL for the live-site audit (headers, .env/.git exposure probes, broken-link crawl). The paste-code path is the one most scanners don't offer.
Does the free scan catch exposed Supabase keys?
Yes, the secrets check runs on the Free tier with 15 basic patterns including common key shapes. Pro expands to 32 patterns and adds blast-radius analysis plus rotation runbooks for every leaked secret.
Will the scanner fix my code?
It doesn't edit your code. Every finding ships with plain-language explanation and copy-paste fix guidance, including prompts you can paste back into Lovable to get the fix generated correctly.
Is a scan a guarantee my app is secure?
No. It's a strong pre-deploy filter for the most common and most dangerous patterns. Nothing replaces a professional penetration test for a high-value target, but scanning catches the issues that actually breach most small apps.