All posts
·13 min·Alex Werner

Vibe coding security: what to check before you ship

Vibe coding changed who ships software. A prompt and an agent now turn an idea into a deployed, internet-facing app in an afternoon - no team, no code review, no tech lead, no security engineer. That is the magic, and it is also the problem. The vulnerabilities did not disappear when the team did. The AI just writes them for you, confidently, and you ship them.

This is the part nobody tells you when they sell you the agent: every guardrail that used to stand between a junior's code and production was a person. A senior who caught the SQL string concatenation. A reviewer who asked "wait, is this endpoint authenticated?" A tech lead who refused to merge a hardcoded key. Vibe coding removes those people from the loop. A first-time builder skips the decade of scar tissue a senior earned the hard way. And the senior, now wielding an agent, ships entire applications that an entire team would once have gated.

So this is the missing checklist. It is built from the threat feed we maintain - 500+ real, post-mortemed breaches across web apps, APIs, cloud, the software supply chain, and AI systems - condensed into what a vibe coder actually needs to look out for. Read it once and you have the map.

TL;DR - the 10 rules

If you read nothing else, internalize these. Each maps to a section below.

  1. Never put a secret in your code. Not in the source, not in the frontend, not committed "just for now."
  2. Assume every endpoint is public until you prove it checks who's asking. Authentication is not authorization.
  3. Turn on your database's row-level security before you ship, not after the leak.
  4. Let the framework escape and parameterize for you. Don't hand-build SQL or HTML from user input.
  5. Treat all user input as hostile - in your code and in any AI feature you ship.
  6. Read the code your agent writes. You are the review layer now. There is no one behind you.
  7. Verify every dependency the AI suggests exists before you install it.
  8. Default everything to private - buckets, databases, admin panels, debug endpoints.
  9. Rotate any secret that ever touched a repo. Deleting the commit does not delete it.
  10. Add a real review and scanning gate before code reaches production. The agent is not a reviewer.

Why vibe-coded apps are uniquely exposed

This is not a hunch - it is measured. In Veracode's 2025 study of AI-generated code, 45% of AI-written samples introduced an OWASP Top 10 vulnerability, with an 86% failure rate on cross-site scripting. A Stanford study found developers using an AI assistant wrote less secure code while being more confident it was secure - the exact combination that ships flaws. The model predicts statistically likely code; secure-by-default is not its objective unless you make it one.

And the consequences are already in the feed. The Tea app breach exposed users' government IDs and selfies from a rapidly built app with an unsecured storage bucket and hardcoded keys. A flaw in the no-code/AI builder Lovable (CVE-2025-48757) left generated apps with row-level security off by default, so anyone could read other users' data through the public API. The pattern is consistent: the app worked, demoed great, and was wide open.

The rest of this post is the do/don't list, ordered by what actually bites vibe coders first.

1. Secrets: never ship a key in your code

This is the single most common vibe-coding mistake, and the most damaging. AI assistants are actively driving a surge in leaked credentials; tens of millions of secrets leak to public GitHub every year.

Don't:

Do: Load secrets from environment variables or a secrets manager at runtime. Add *.env and key files to .gitignore. Turn on pre-commit secret scanning and your host's push protection so a key never reaches the remote. And if a secret ever touched a repo, rotate it immediately - assume it is compromised. (See all secrets-in-code cases →)

2. Auth and access control: don't ship a public app

A vibe-coded app that "works" usually means the happy path works. The dangerous default is an API that returns data to anyone who asks, or an endpoint that checks you're logged in but never that the record is yours.

Don't:

  • Ship an endpoint that serves a record by ID without checking it belongs to the caller. This is Broken Object Level Authorization (IDOR), the most common API flaw, and it is how First American leaked 885M documents (just increment the number in the URL), how Optus lost 9.8M customer records, and how T-Mobile lost 37M.
  • Confuse authentication with authorization. The USPS API required login but let any logged-in user read any other user's account. Peloton's API returned private profiles to anyone.
  • Trust the client to enforce anything - privacy flags, prices, user roles. Enforce it server-side.
  • Bind request bodies straight to your database model. Mass assignment is how a researcher gave himself commit access to the Rails repo by setting a field the form never showed.
  • Leave row-level security off (the Lovable and Tea failure).

Do: Enforce object-level authorization on every request - check the resource owner against the session, every time. Require auth on every route, including the ones you forgot you shipped. Turn on row-level security in Supabase/Postgres and test anonymous access against every endpoint before launch. Bind only an explicit allowlist of fields. (See all AppSec cases →)

3. The classic bugs the AI writes for you

The agent will, unprompted, hand you the vulnerabilities that have headlined breaches for twenty years. The good news: modern frameworks defend against all of them if you use their defaults instead of letting the AI roll its own.

Do: Stick to your framework's secure defaults, and run a static-analysis scanner over AI-generated code before merge - these classes are exactly what scanners catch.

4. Your coding agent is part of the attack surface

The agent does not just write risky code - it can be turned against you.

Don't:

  • Install a package just because the AI suggested it. Models hallucinate package names, and attackers pre-register those names with malware - this is slopsquatting. Verify the package actually exists and is legitimate first.
  • Trust files the agent reads. Hidden instructions in a README, a dependency, a web page, or an agent rules file can hijack the agent into inserting a backdoor or exfiltrating your secrets.
  • Let the agent auto-run shell commands or auto-merge its own output. The nx supply-chain attack weaponized developers' own local AI CLIs to scan for and steal their secrets; a poisoned Amazon Q extension shipped a wipe-the-machine instruction; a Replit agent deleted a production database.
  • Give the agent standing access to production. Separate dev and prod; deny the agent write access to live data and keys.

Do: Pin and lockfile dependencies, vet new ones, sandbox agent execution, require approval before it runs commands, and read every diff before you accept it. (See all AI coding-agent cases →)

5. If your app ships an AI feature or chatbot

The moment your app has an LLM that reads user input or external data, prompt injection becomes your problem. The model cannot tell your instructions from an attacker's.

Don't:

  • Concatenate user input into your system prompt. The first viral case - the remoteli.io bot - and the Chevrolet dealership bot that "sold" a car for $1 both did exactly this.
  • Render the model's output as raw HTML. Lenovo's chatbot was turned into a cookie-stealing XSS because its output was injected into the page unsanitized.
  • Put secrets, .env, or privileged data in the model's context - it can be coaxed out, and an X crypto agent was drained of $150K through an injected instruction.
  • Let an agent that reads untrusted data (emails, support tickets, CRM leads, documents) take real actions without approval. That is ForcedLeak (CRM exfiltration via a lead form) and EchoLeak (zero-click exfiltration from an email) - the excessive-agency trap.
  • Forget you're liable for what it says: a tribunal held Air Canada responsible for its chatbot's invented policy.

Do: Treat all input and all ingested content as untrusted data, never as instructions. Sanitize and encode model output before rendering. Keep secrets out of the prompt. Require human approval for any consequential action, and scope the agent's tools to least privilege.

6. Deploy: don't expose your data to the internet

Vibe coding doesn't stop at the code - you deploy it, and the cloud console is its own minefield of insecure defaults.

Don't:

Do: Default everything to private. Enable "block public access" on storage. Put databases on private networks behind auth. Scope cloud roles to least privilege, enforce IMDSv2, and never ship that .env. (See all cloud/IaC cases →)

7. Dependencies and the supply chain

Your app is mostly other people's code. Attackers know it, and they target the packages you pull in - worms that spread through npm, hijacked popular packages, and dependency confusion.

Do: Pin versions and commit a lockfile. Add dependency scanning to catch known-vulnerable and newly-published suspicious packages. Be especially wary of anything the AI suggested by name. (See all supply-chain cases →)

The minimum-viable security checklist

Print this. Run it before every launch.

  • No secrets in source, frontend, or git history - all loaded from env/secrets manager
  • Secret scanning + push protection enabled; any exposed secret rotated
  • Every endpoint requires auth and checks the resource belongs to the caller
  • Row-level security on; anonymous access tested against every endpoint
  • Framework defaults used for SQL (parameterized) and HTML (auto-escaped); CSP set
  • User-supplied URLs validated (no SSRF); file uploads can't execute
  • Dependencies pinned, lockfiled, scanned; AI-suggested packages verified to exist
  • AI agent can't auto-run commands or auto-merge; every diff reviewed; no prod access
  • Any shipped LLM feature treats input as untrusted, sanitizes output, keeps secrets out of the prompt, and human-approves real actions
  • Buckets/databases/admin panels private by default; cloud roles least-privilege
  • A real review + static-analysis gate runs before code reaches production

Frequently asked questions

Is vibe coding secure?

Vibe coding is not inherently insecure, but AI coding agents produce insecure code by default - studies have found roughly 45% of AI-generated code contains an OWASP Top 10 vulnerability. The bigger risk is process: vibe coding removes the human review, tech-lead approval, and security checks that used to catch those flaws before production. Vibe-coded apps can be perfectly safe, but only if the builder adds back the review, scanning, and secure-default practices the team used to provide.

What is the biggest security risk in vibe coding?

The two most common and damaging mistakes are hardcoded secrets (API keys and credentials committed into code, including the frontend) and missing access control (endpoints that return data without checking the requester is authorized for that specific record). Both have caused massive real-world breaches and both are shipped routinely by AI agents that optimize for working code, not secure code.

Do I need to review code my AI agent writes?

Yes. In vibe coding you are the review layer - there is no senior engineer or security team behind you. AI agents reliably emit classic vulnerabilities like SQL injection, cross-site scripting, and hardcoded secrets, and they can also be hijacked through hidden instructions in files they read. Reading every diff before accepting it, plus running an automated security scanner, is the minimum safe practice.

How do I keep secrets out of my vibe-coded app?

Never write secrets as string literals in code. Load them from environment variables or a secrets manager at runtime, add env and key files to gitignore, and enable pre-commit secret scanning plus your host's push protection so a key cannot reach the remote. If a secret ever reached a repository, rotate it immediately - deleting the commit does not remove it from git history, and anyone who cloned the repo still has it. Never put a real key in frontend or mobile code, because anything shipped to the client is readable by anyone.

Can I trust the dependencies my AI assistant suggests?

No, not without checking. Language models hallucinate package names that do not exist, and attackers pre-register those hallucinated names with malware - an attack class called slopsquatting. Always verify a suggested package actually exists and is legitimate (real downloads, maintainer, and repository history) before installing it, pin versions, commit a lockfile, and scan dependencies for known issues.

My app uses an AI chatbot or agent - what should I watch for?

Prompt injection. The model cannot distinguish your instructions from an attacker's input, so any user message or ingested content (email, document, CRM lead) can hijack it. Never concatenate user input into your system prompt, never put secrets in the model's context, sanitize and encode the model's output before rendering it, scope the agent's tools and permissions to the minimum, and require human approval before the agent takes any consequential action like sending data or moving money.

The bottom line

Vibe coding gave individuals the output of a whole team. It did not give them the team's judgment - the senior who catches the unparameterized query, the reviewer who asks "is this authenticated?", the security engineer who blocks the hardcoded key. That judgment is what this checklist encodes, distilled from hundreds of real breaches.

This is also exactly why I built Stateward. It is the review layer the team used to be: it reviews every pull request inline, checks every dependency against this same threat feed of real-world attacks, hunts for the secrets and the missing authorization checks an agent leaves behind, and tells you what is actually exploitable - before it ships. Vibe code fast. Just don't ship it blind.

Want this kind of review on your own pull requests?

Get started free