// docs / security guides / ai-code scanner
AI-generated code security scanning: DAST for vibe-coded apps
Apps built with Cursor, Claude Code, Lovable, Bolt, v0, Replit, and Windsurf ship faster than any prior generation of web software — and they ship with a predictable set of security gaps. This page explains why AI-generated apps need different scanning than traditional pentest tools, which vulnerability classes are over-represented, how DAST differs from SAST when the codebase is half-machine-generated, and what to look for in a scanner built for this workload.
Why AI-generated code needs different security scanning
AI coding tools are trained on open-source repositories at scale. That training data skews toward make it work over make it secure. A few structural patterns follow from that:
- Autocomplete bias. The nearest matching import wins. Pasting a Supabase snippet that uses the
service_rolekey in one file makes that key the autocomplete suggestion in the next — even in client-side React components where it never belonged. - No long-term context. An LLM has no memory of your last RLS bypass or your team's incident postmortem. Each generated file is fresh, often missing defensive patterns that humans would carry across files.
- Speed as the rewarded metric. Users praise speed; LLM training reinforces it. "Generate the fastest Next.js auth" beats "generate the most secure Next.js auth" on latency feedback signals.
- Training data gaps. Older codebases dominate training data and predate modern security defaults (strict CSP,
SameSite=Lax, HSTS, RLS). Generated code echoes patterns that were normal in 2019 but unsafe today. - Implicit platform trust. When Cursor generates a Vercel app it assumes Vercel's defaults are secure. Some are (auto-HTTPS, signed cookies). Many aren't (no CSP by default, permissive CORS, default Next.js debug routes).
Ten vulnerability classes over-represented in vibe-coded apps
The same finding classes show up disproportionately in AI-generated apps:
- Exposed Supabase service-role keys. A
service_roleJWT (startseyJ) committed to a client bundle bypasses every RLS policy on the project. Cursor autocompletes it on the wrong side of the boundary; the key ships in/_next/static/.... - Missing Row-Level Security (RLS). The model sees
CREATE TABLE public.itemsand proceeds without enabling RLS. Anonymous users can then read or write any row via the public anon key. See Supabase Row-Level Security. - Open Firebase / Firestore rules. Generated rules files often read
allow read, write: if true;or skip the rules file entirely. Test-mode rules let anyone read and overwrite data until someone replaces them. - Hardcoded API keys in bundles. Stripe live keys, Anthropic
sk-ant-*, OpenAIsk-*, GoogleAIza*, and AWSAKIA*keys end up inlined into JS payloads when env-var discipline lapses. Secrets in JavaScript Bundles flags them at the rendered-page level. - Missing Content Security Policy. No
Content-Security-Policyresponse header means every inline-script XSS is one click away from full account takeover. CSP is abstract; codegen routinely skips it. HTTP Security Headers reports the gap with deploy-platform-specific fix guidance. - Next.js middleware misplacement. With the
src/layout, Next.js only picks upsrc/middleware.ts— a root-levelmiddleware.tsis silently ignored. Auth still appears to work because pages callrequireAuth(), but headers, CSP, and rate limits don't land. - IDOR via unsigned IDs. Generated
GET /api/items/[id]handlers trust the path parameter and never verify ownership. Walking the integer or UUID space exposes every tenant's data. - Broken auth flows. Magic-link tokens with no
expires_at; JWT verification that skipsaudandexp; client-sidegetSession()calls (which read an unverified cookie) instead of server-sidegetUser(). - Debug endpoints in production. Generated
/api/debug,/api/health,/api/__nextjs_original-stack-frame, or/.next/traceroutes leak internals. FixVibe reports them only with evidence that they really are exposed (Vercel-Specific Exposure). - Plaintext sensitive fields. Passwords, API keys, and PII stored as plain text in Postgres because the migration didn't reach for
pgcryptoor an external vault.
DAST vs SAST: why both matter for AI-generated code
Static analysis (SAST) and dynamic analysis (DAST) are complements, not substitutes. The split matters more for AI-generated code than for hand-written code.
SAST reads source code on disk. It catches secrets in source files, dangerous function calls, and risky patterns before the build runs. It cannot see runtime configuration, deployed environment variables, or how a bundler transformed your code.
DAST hits the deployed application like a user. It sees shipped responses, runs against the production bundle, and catches config drift between repo and deploy. It finds hardcoded keys in transpiled JavaScript that SAST never saw because they entered via a process.env assignment at build time.
For AI-generated code, DAST is essential because what ships differs from what the model wrote. Bundling, tree-shaking, transpilation, and environment-variable inlining all create new surfaces. SAST on source can miss bundle-embedded secrets entirely. DAST catches both layers. A mature pipeline runs SAST in CI and DAST against the deployed preview — that's the FixVibe pattern.
What to look for in an AI-code scanner
Most general-purpose DAST scanners (Burp Suite, OWASP ZAP, Nessus) were designed for monolithic apps and traditional auth flows. Scanning a Vercel + Supabase + Stripe AI-generated app needs:
- BaaS coverage. Real checks against Supabase RLS, Firebase / Firestore rules, Clerk config, AWS Amplify, and the JWT shapes those services emit. Generic OWASP rules don't know what to flag.
- JS bundle inspection. Recognising real API-key formats — Stripe
sk_live_, Anthropicsk-ant-, Supabase service-role keys — and telling a secret key from a publishable one. Generic pattern matching throws too many false positives. - Passive + active split. Passive checks (headers, cookies, secrets, BaaS config, DNS) run safely against any URL. Active probes (SQLi, XSS, SSTI, IDOR walking) require an authorization boundary because they fire attack-style payloads.
- Framework awareness. Recognising Next.js App Router vs Pages Router, Vite SPA rewrites, Vercel deployment-protection, Cloudflare Pages routing. A scanner that doesn't understand how these platforms answer unknown paths generates noise.
- Rate-limit safety. Bounded request budgets per scan, and findings that require positive evidence — a blanket
403from a WAF is not proof a file exists. - Authorization gating for intrusive payloads. Sending SQLi or OS-command payloads to a domain you don't own is illegal in most jurisdictions. A real scanner requires DNS or HTTP-file ownership verification before letting you run active mode against a target.
FixVibe's approach: evidence-based scanning, low false-positive load
FixVibe is a DAST built specifically for AI-generated web apps. The passive phase runs 230+ checks on the rendered page (headers, CSP, cookies, leaked secrets, BaaS misconfiguration, tech fingerprinting, DNS, attack-surface discovery). The active phase adds payload-firing probes (SQLi, XSS, SSTI, CORS, redirects, IDOR walking, CSRF, account enumeration, blind-SSRF) gated behind verified-domain ownership. Repo scans add code-phase checks against connected GitHub repositories. Every finding includes evidence, a CWE link, a remediation recipe, and either a coding-agent prompt or operator steps depending on who can actually apply the fix. The scan engine is open in the changelog — every new check, accuracy improvement, and false-positive fix is logged publicly.
FixVibe vs Burp Suite, ZAP, and Nessus: when each tool wins
No single tool covers every workflow. For a sourced side-by-side of FixVibe, Burp Suite, ZAP, Snyk, Semgrep and Aikido, with a decision matrix, see choosing a security scanner for AI-built apps.
Where the tools complement each other
- Start with FixVibe passive as a free baseline against any deploy preview — it usually finishes in under a minute. If nothing surfaces, you have a fast confidence signal.
- Move to FixVibe active on a verified domain when you want full active coverage (SQLi/SSTI/IDOR/etc.) against your own infrastructure.
- Layer SAST (Semgrep, CodeQL, Snyk) on the source code in CI. SAST catches what runtime can't see — risky patterns in code paths that never reach the deploy.
- Reach for Burp Suite when you need custom attack chains (specific auth bypasses, intricate IDOR scenarios, business-logic flaws). Burp is the deepest manual workbench available; FixVibe is the fastest automated baseline.
Next steps
Continue with the Vibe coding security checklist for a 51-item pre-ship audit, or jump to How to secure an app built with AI coding tools for step-by-step hardening with code snippets.
