← Blog
·10 min read

Why AI Writes Insecure Code: The Vibe Coding Security Problem

The root cause of vibe coding security problems. Why AI coding tools write insecure code — training data, optimization targets, and context limitations explained.

Rod

Founder & Developer

There's a version of this story where AI tools are the problem and developers are the victims. That version is too simple. The vibe coding security problem isn't really about AI being malicious or broken. It's about a structural mismatch between how these tools work and what security actually requires.

Understanding why AI writes insecure code matters more than a list of what it gets wrong. Fix the mental model, and the checklist makes sense. Skip the model, and you're just pattern-matching without knowing why the patterns matter.


The Training Data Problem

Every AI coding tool learns from code. Cursor, GitHub Copilot, Claude, Gemini — they all ingested billions of lines from public repositories, documentation, Stack Overflow answers, and tutorials.

Here's the thing about that corpus: it's full of insecure code.

Not because developers are careless. Because historically, security wasn't the primary concern when code was written and shared publicly. Open source libraries prioritized functionality. Tutorial code prioritized clarity. Hackathon projects prioritized shipping. Security was something you added later — or, often, never.

A model trained on that data learns what "real code" looks like. And real code, statistically, has hardcoded credentials, unvalidated inputs, and missing auth checks. The model reproduces those patterns because that's what the training distribution rewarded.

Veracode's 2025 State of Software Security report found that 45% of AI-generated code contains at least one vulnerability. This isn't surprising if you understand where the model learned to write code. It's the expected output of a model trained on the existing codebase of the internet.


The Wrong Optimization Target

Machine learning models optimize for whatever signal you train them on. For code generation, that signal is roughly: "does the generated code look like correct, useful code that developers would accept?"

Notice what's missing from that objective.

"Does this code expose user data?" — not in the objective. "Does this route require authentication before returning sensitive information?" — not in the objective. "Does this pattern allow an attacker to bypass access controls?" — not in the objective.

The RLHF (Reinforcement Learning from Human Feedback) process used to fine-tune these models makes them better at generating code developers approve of. Developers approve of code that works. They're less likely to catch a subtle authorization flaw in a code review than they are to notice a syntax error or logic bug.

So the model gets rewarded for generating code that compiles, that does the described thing, and that looks plausible. Security properties — which often require understanding the full system — don't show up cleanly in token-by-token approval signals.

This isn't a temporary flaw to be patched. It's a consequence of how the training process works. Some newer models are being fine-tuned specifically on secure code examples, and that helps. But the optimization target is still fundamentally about code correctness, not code safety.


The Context Window Problem

This is the one people underestimate.

When you ask Cursor to write a new API route, the model sees:

  • Your prompt
  • The current file
  • A few related files (if you've added them to context)

What it doesn't see:

  • Your middleware configuration
  • Your auth session management logic
  • Your database schema and access patterns
  • Your environment variables and which ones exist
  • The other 47 routes in your app and how they handle auth
  • Your threat model — what attackers are likely to do, what data is sensitive

Security is a system-level property. A route is secure or insecure not just based on its own code, but based on how it interacts with auth middleware, database policies, and every other part of the system.

The AI can generate a route that looks perfectly reasonable in isolation and is a serious vulnerability in context. The common case: the AI generates a route that expects authentication to be handled upstream (by middleware it doesn't know exists, or doesn't know is configured correctly). The route ships. The middleware has a gap. The route is accessible unauthenticated.

OWASP calls this Broken Access Control — the number one vulnerability category in the OWASP Top 10 for multiple consecutive years. It's number one because context is hard. AI tools make it harder, because they generate code that looks contextually correct while lacking the actual context.


The Temporal Knowledge Gap

AI models have a training cutoff. Cursor, Copilot, and similar tools know about the vulnerability landscape as it existed at some point in the past — possibly 12-24 months before you're using them.

This matters for dependencies. When an AI suggests npm install some-library or scaffolds a package.json, it installs versions it knows from training. Those versions may have had CVEs (Common Vulnerabilities and Exposures) discovered since the model was trained. The model has no knowledge of those CVEs. It doesn't suggest a safer version because it doesn't know the old version is unsafe.

This is also why npm audit after AI scaffolding is not optional. The model optimized for a package that was safe when it learned about it. Reality has moved on.

The dependency problem compounds over time. A repo scaffolded 12 months ago with AI-suggested packages has had 12 months of CVEs accumulate. Without an active maintenance process, the security posture degrades passively.


The "Happy Path" Bias

AI tools excel at the happy path. You describe the intended behavior, the model generates code that implements it.

Security, by definition, is about the unhappy path: what happens when a user sends something you didn't expect? What happens when an attacker sends '; DROP TABLE users;-- where you expected an email address? What happens when the session token is forged?

The model doesn't generate attack scenarios because you didn't ask for them. It generates code that handles normal inputs correctly, because that's what you described and that's what looks like "correct" code in training data.

This is the fundamental gap. A developer thinking about security thinks: "What could go wrong here?" An AI generating code thinks: "What does the code need to do to satisfy this prompt?" Those are different questions.

The result isn't malicious. It's that the AI produces code for the world it was asked about — one where inputs are well-formed, users are honest, and everything works as expected. Security requires imagining a different world.


What This Means in Practice

Understanding the root cause changes how you think about using AI coding tools.

The AI isn't lying to you. When it generates code that has a vulnerability, it's not hiding something. It genuinely doesn't know — because knowing requires system-level context and adversarial thinking that isn't part of its optimization objective.

Reviewing AI code for security is different from reviewing it for correctness. Reading the code to check if it does what you asked is not the same as reading it to check if it can be exploited. Security review requires explicitly asking "what can go wrong?" for every piece of user-supplied input that touches the code.

The fix isn't to stop using AI tools. The fix is to add the step the AI can't do: a system-level security audit after the code is generated. Automated scanners can catch the pattern-level vulnerabilities — hardcoded secrets, dependency CVEs, missing headers — and surface them for human review. That's the gap that needs to be closed.

If you've built something with vibe coding and haven't done that audit yet, the vibe coding security risks guide covers the five most common vulnerability categories in detail. For a step-by-step pre-launch checklist, the secure vibe coded app guide walks through every check.


The Scan Fills the Context Gap

Data Hogo's scanner does what the AI can't: it sees the full system. All routes, all dependencies, deployed URL headers, database configuration. It's not reasoning from a prompt — it's analyzing your actual codebase for patterns that are known to be problematic.

The combination works: AI for generating code fast, scanner for auditing the output with full context. That's the workflow that closes the security gap without slowing down the development pace.

Scan your repo free →


Frequently Asked Questions

Why does AI-generated code have security vulnerabilities?

AI coding tools are trained on code from public repositories, which historically contained insecure patterns because developers optimized for functionality, not security. The models learned from this corpus and reproduce its patterns. Additionally, AI tools optimize for correctness (does the code run?) not security (does the code protect user data?), and lack the system-level context to catch vulnerabilities that only appear when multiple components interact.

Is vibe coding fundamentally insecure?

Vibe coding isn't fundamentally insecure — it's fundamentally unreviewed. The security gap isn't in the AI's output; it's in the absence of an audit step between AI output and production deployment. With a scan and targeted fixes, vibe-coded apps can reach the same security baseline as hand-written code. The issue is that most vibe coding workflows don't include that step.

Do AI coding tools know about security?

AI tools have been exposed to security knowledge — OWASP guidelines, vulnerability discussions, security blog posts — and can generate secure code when prompted correctly. The problem isn't ignorance; it's the optimization target. When you ask for a login route, the AI optimizes for a working login route. Whether it's protected against timing attacks or credential stuffing isn't part of the default objective.

Will AI coding tools get better at security?

Yes, over time. Some models are already being fine-tuned specifically on secure code. GitHub Copilot has a security-aware mode. The trend is toward tools that flag insecure suggestions in real time. But the fundamental context limitation won't be fully solved soon — an AI generating a function still can't see your full application, your deployment environment, or your threat model.

What is the most dangerous security pattern AI tools produce?

Hardcoded credentials are the most immediately dangerous — a leaked API key can be exploited within minutes by automated bots. Missing authentication checks are the most structurally dangerous — an unprotected admin route can expose your entire database to anyone who finds it. Both patterns appear consistently in AI-generated code because neither requires the tool to understand the full system context.

vibe-codingsecurityai-coderoot-causellm