·6 min read

Vibe Coding Is a Security Risk: The Hidden Cost of AI-Generated Code

Developers are shipping AI-generated code faster than ever. Security researchers are finding the vulnerabilities just as fast.

CVE-2024-3094 sat in XZ Utils for weeks before Andres Freund noticed SSH was taking an extra 500 milliseconds on a Debian box. That’s the part people remember because it’s elegant: one weird latency blip, one careful engineer, one near miss. The less romantic part is that it took a tiny signal to catch a supply-chain compromise that had already made it into widely used Linux distributions. Vibe coding is headed for the same punchline, except the compromised artifact is your own application code and the attacker may not even need to hide.

AI-Generated Code Ships Fast; Security Bugs Ship Faster

GitHub’s own research has said Copilot can make developers complete coding tasks faster, and that is exactly why teams are now merging code they do not fully understand. Security researchers have been demonstrating the downside for two years: insecure defaults, broken auth flows, and logic bugs that look plausible enough to pass a rushed review. In 2023, researchers showed that code assistants routinely produced vulnerable patterns like SQL injection and hardcoded secrets when prompted in common web-app scenarios. The problem is not that the model “knows” nothing; it’s that it confidently emits code that looks like something a tired engineer would have written after three coffees and a deadline.

The usual defense is that “human review will catch it.” Sometimes. In practice, review quality drops when the diff is large, the reviewer is not the domain owner, and the code is syntactically clean enough to avoid suspicion. That is exactly the trap: AI-generated code is often polished on the surface and rotten in the seams. A hand-written bug tends to have fingerprints. Generated code often has a veneer of consistency that makes reviewers over-trust it, especially when the author says the model “just scaffolded it.”

The Bugs Security Teams Keep Finding in Copilot, Cursor, and ChatGPT Output

The recurring failures are boring in the way real incidents are boring. Authentication checks get bolted on after the fact. Input validation is partial, inconsistent, or missing on the one endpoint that matters. Secrets end up in config files because the model happily mirrors patterns from public repos. In one widely cited study, researchers found that developers using AI assistants were more likely to accept insecure suggestions when they were framed as idiomatic or “best practice” code. That is not a model problem so much as a human one: people trust code that looks familiar.

You can see the same pattern in the wild with frameworks and libraries that are easy to misuse. A generated Flask route that forgets CSRF protection is not exotic. A Node.js API that trusts a client-supplied role claim is not novel. A React app that leaks an API key into the browser bundle is not a “theoretical” issue; it’s the sort of thing that ends up in bug bounty reports and then in incident response when the key gets abused. If your AI tool is trained on public examples, it will gladly reproduce the public mistakes.

Why “Just Add a Scanner” Does Not Save You

Static analysis is useful, but it is not a magic priesthood that absolves bad engineering. Semgrep, CodeQL, and similar tools can catch obvious injection sinks, unsafe deserialization, and sloppy crypto usage. They do not reliably catch business-logic failures, authorization gaps, or security assumptions that are wrong by design. If a model generates code that checks a token but never verifies the issuer, a scanner may shrug because the code is perfectly valid and completely broken.

This is where the standard advice gets lazy. Teams keep saying they need “more guardrails,” as if the answer is to wrap a broken process in another broken process. The real issue is provenance. If you cannot tell which parts of a feature were written by a developer, copied from Stack Overflow, or hallucinated by Claude, then your review process is already degraded. Security teams should care less about whether the code was “AI-assisted” and more about whether anyone can explain why it is safe.

The Contrarian Bit: AI Code Is Not Automatically Worse

Here’s the uncomfortable part: AI-generated code is not always the weakest link. A competent engineer using a model for boilerplate can produce cleaner, more consistent code than a junior developer hand-rolling auth middleware from memory. The risk is not that every generated function is a disaster. The risk is that teams use the speedup to justify thinner review, broader scope, and less testing. In other words, the model is not the vulnerability; the process that surrounds it is.

That is why blanket bans are mostly theater. Developers will route around them, paste code into personal accounts, or use local models with no logging at all. Better to assume AI-written code is already in your repo and build controls around that reality. Treat it like any other untrusted supply chain: inspect it, test it, and make sure you can trace where it came from. If you can’t, you are doing security by vibes, which is apparently on brand.

The Checks That Actually Catch This Stuff

Start with the boring controls that still work. Require threat modeling or at least a security review for any AI-assisted feature that touches auth, payments, file upload, or tenant isolation. Run Semgrep or CodeQL in CI with rules tuned for your stack, not generic “best effort” defaults. Add unit tests that specifically assert negative cases: unauthorized users cannot read other tenants’ records, expired tokens fail, malformed input is rejected, and secrets never reach client-side bundles.

Then do the thing people hate because it slows them down: diff review for intent, not syntax. Ask reviewers to explain the trust boundaries in the code, not whether the indentation looks nice. If the author cannot describe how the generated code handles input validation, session state, or privilege checks, the feature is not ready. Also log the prompt or generation context for sensitive modules. Not because it is glamorous, but because when something breaks, “the model suggested it” is not an incident report.

The Bottom Line

If AI-generated code is entering your repo, treat it as third-party code with no warranty and no memory of your architecture. Put Semgrep or CodeQL in CI, require explicit security review for auth and data-access paths, and make reviewers explain the trust boundaries before merge. For anything customer-facing, add negative tests for authorization, input validation, and secret handling; if those tests are missing, the feature is not done.

References

← All posts