Is vibe coding bad? No, not by itself. Describing what you want and letting an AI write the code is a genuinely faster way to build software. What is bad is shipping that code to real users without anyone checking it, because AI coding tools optimize for code that runs, not code that is safe. The rest of this guide explains where that gap shows up, with real examples, and gives you a vibe coding security checklist you can run before launch.

The term comes from Andrej Karpathy, who in February 2025 described "a new kind of coding I call vibe coding, where you fully give in to the vibes, embrace exponentials, and forget that the code even exists." That last part, forgetting the code exists, is fine for a throwaway project. It is exactly the problem when the project stores customer data.

The case for vibe coding

It is worth being fair before listing risks. Vibe coding with tools like Cursor, Claude Code, Lovable, Bolt, v0 or Replit has real advantages:

  • Speed. A working prototype in hours instead of weeks. Founders validate ideas before hiring a team.
  • Access. Designers, product managers and domain experts can build tools they previously had to request.
  • Less boilerplate. Experienced developers skip repetitive CRUD, forms and glue code and spend time on the hard parts.
  • Fast iteration. Changing a flow is a prompt, not a sprint.

None of that is a security problem. The problem is what disappears along the way: the code review, the senior developer who notices a key in the wrong file, the staging environment, the moment where someone asks "who is allowed to call this endpoint?"

What the research says

This is not only anecdote. A few data points worth knowing:

  • Insecure output is common. Veracode's 2025 GenAI Code Security Report tested code from more than 100 large language models on Java, JavaScript, Python and C# tasks and found that 45% of the code samples failed security tests and introduced OWASP Top 10 vulnerabilities.
  • Models invent packages. The USENIX Security 2025 paper "We Have a Package for You!" generated 576,000 code samples with 16 models and found that 19.7% of the recommended packages did not exist. An attacker who registers one of those names gets code execution on every machine that installs it.
  • Real apps were exposed. CVE-2025-48757 described Lovable-generated projects with insufficient Row Level Security policies, which let unauthenticated attackers read or write database tables. The researcher who reported it found more than 170 affected apps.

The vibe coding security risks that show up again and again

RiskWhat it looks likeImpact
Hardcoded secretsAPI keys in source files, .env committed to git, secrets in client bundlesAccount takeover of your providers, surprise bills, data access
Missing authenticationAPI routes that return data without checking a sessionAnyone on the internet can read or modify data
IDORSession checked, but not who owns the recordUser A reads User B's invoices by changing an ID
Insecure defaultsCORS *, debug mode, verbose errors, cookies without Secure or HttpOnlyToken theft, information leaks, easier exploitation
Hallucinated or typosquatted packagesDependencies that do not exist or are one letter off a popular oneMalicious code running in your build and servers
Exposed Supabase keys and RLS offSecret or service_role key in the browser, tables without Row Level SecurityFull database read and write from the browser console
InjectionSQL or shell commands built with string concatenationData theft, remote code execution
Weak CI and infrastructure configGitHub Actions with broad tokens, Dockerfiles running as root, public bucketsSupply chain compromise, lateral movement

1. Hardcoded secrets

The AI puts the key wherever the code needs it. If that is a React component, the key ships to every visitor's browser. If it is a config file, it lands in git, and deleting it later does not remove it from history.

// lib/ai.ts (imported by a client component)
const openai = new OpenAI({ apiKey: "sk-proj-..." });

// next.config.js
env: { NEXT_PUBLIC_STRIPE_SECRET: process.env.STRIPE_SECRET_KEY }

Anything prefixed NEXT_PUBLIC_ (or VITE_ in Vite) is bundled into client code. Secrets belong in server-only code, and any key that ever reached a browser or a commit should be rotated, not just removed. Our comparison of secret scanning tools covers how to search the full git history, and a secret scanner can run that on every push.

2. Missing authentication

// app/api/orders/route.ts
export async function GET() {
  const orders = await db.order.findMany();
  return Response.json(orders); // every order, for anyone
}

The prompt was "show the orders page". The model made it work. Nobody asked who should see it.

3. IDOR: the bug that looks correct

// app/api/invoices/[id]/route.ts
export async function GET(req: Request, { params }) {
  const session = await auth();
  if (!session) return new Response("Unauthorized", { status: 401 });
  const invoice = await db.invoice.findUnique({ where: { id: params.id } });
  return Response.json(invoice); // no check that invoice.userId === session.user.id
}

There is a login check, so it passes a quick review. But any logged-in user can iterate IDs and read everyone's invoices. This is an IDOR vulnerability, part of broken access control, which leads the OWASP Top 10. The fix is to scope the query: where: { id: params.id, userId: session.user.id }.

4. Insecure defaults

Models reach for whatever makes the error go away. A CORS error becomes Access-Control-Allow-Origin: * with credentials. A failing cookie becomes a cookie without Secure. A crash becomes a stack trace returned to the client. Each one is small; together they make every other bug easier to exploit.

5. Hallucinated and typosquatted packages

When the model suggests npm install or pip install for a package, check that it exists, that it is the one you meant, and that it has a real maintainer and history. Attackers publish packages with names that models tend to invent (sometimes called slopsquatting) and with names one keystroke away from popular ones. Pin versions and commit your lockfile.

6. Exposed Supabase keys and Row Level Security

Supabase is the default backend for many vibe-coded apps, and its documentation is explicit: a table in an exposed schema without RLS is readable and writable by any role with a grant on it. Only the publishable key (or the legacy anon key) is meant for the browser, and it is only safe because RLS limits what it can reach. A secret or service_role key bypasses RLS and must never leave the server.

alter table public.invoices enable row level security;

create policy "owners read their invoices"
  on public.invoices for select
  using ( auth.uid() = user_id );

We cover policies in depth in the Supabase RLS guide.

When vibe coding is fine and when it is risky

ProjectRiskMinimum review
Personal prototype, no real usersLowKeep secrets out of the repo
Internal tool behind company loginMediumSecret scan, dependency check, auth on every route
Public app with user accountsHighFull checklist below, automated scan on every change
Payments, health data, B2B customersVery highChecklist, continuous scanning, human pentest before launch

Vibe coding security checklist

Run this before you share the link, and again before you charge money.

Secrets

  • No API keys, tokens or passwords in source files or client bundles.
  • No .env files in git, and the full git history scanned, not only the latest commit.
  • Every key that was ever exposed has been rotated.

Authentication and authorization

  • Every API route that reads or writes data checks the session.
  • Every query that loads a record by ID also filters by owner or tenant.
  • Admin routes check a role on the server, not a flag in the frontend.
  • Test it: log in as user A, request user B's resource, expect 403 or 404.

Database

  • Row Level Security enabled on every table in an exposed schema, with policies scoped to the user.
  • Only the publishable or anon key in the browser; secret and service_role keys only on the server.
  • Queries parameterized, never built with string concatenation.

Dependencies

  • Every package the AI added actually exists and is the intended one.
  • Lockfile committed, known CVEs checked, unused packages removed.

Configuration

  • CORS restricted to your own origins; cookies Secure, HttpOnly and SameSite.
  • Debug mode off and generic error messages in production.
  • Rate limiting on login, signup, password reset and anything that costs money (AI calls, emails, SMS).
  • GitHub Actions with minimal permissions, containers not running as root, no public storage buckets by accident.

How to review a vibe-coded app

Ask the AI for a security pass, but do not stop there. Prompting "review this for security issues" catches some problems, but the same model that wrote the code tends to share its blind spots. Our look at Claude Code security review shows what an assistant-driven review catches and misses.

Run dedicated scanners. Secret scanners, dependency scanners and static analysis catch the mechanical issues cheaply. Our list of open source vulnerability scanners is a good free starting point, and AI SAST adds reasoning about authorization and data flow, which is where IDOR hides.

Use a review built for AI-generated code. For example, with Nurbak you connect GitHub and scan a repository. Its own self-hosted AI model analyzes the code (the analysis does not send your code to OpenAI or Anthropic) and reports exploitable vulnerabilities with file and line, dependency CVEs, GitHub Actions, Docker, Terraform and Kubernetes misconfigurations, and secrets in git history, with a 0 to 100 score and plain-language explanations. It can open a Pull Request with the fix plus a security regression test (the fix uses Claude, only with your explicit consent). The free scan shows the three most important findings in full. See how AI code review for security works.

Bring in humans when the stakes justify it. Business logic flaws and chained attacks still need a person. If you sell to companies, handle payments or store sensitive data, plan a penetration test before a major launch. Our guide to choosing a penetration testing company explains what to ask for, and a code security audit is a lighter option between tests.

Bottom line

Vibe coding is not bad; unreviewed vibe coding is. The same speed that lets you ship in a weekend lets a missing auth check, a leaked key or an invented package ship with it. Treat AI-generated code like code from a fast, talented junior developer: useful, often right, and never merged into production without a review. Run the checklist, automate the scan with an AI code review on every change, and keep humans for the high-stakes moments.

Related reading