ixsoftum
Is vibe coding bad? What actually breaks when nobody reviews the output
AI-assisted developmentStrategic

Is vibe coding bad? What actually breaks when nobody reviews the output

Vibe coding isn't inherently bad, unreviewed output shipped somewhere it matters is. Here's exactly what breaks when nobody checks it, and why.

ixsoftum Editorial·Published 07 Aug 2026·4 min read
Key takeaways
  • Andrej Karpathy coined "vibe coding" in February 2025 for a specific case: throwaway weekend projects where nothing depends on the code staying correct. Most of what breaks under the "is vibe coding bad" question is the practice used past that original scope.
  • The failure mode that recurs most isn't broken features, it's missing negative-space checks: what should be rejected, not what should work. Agents optimize for the happy path they can verify; review is specifically the step that catches what shouldn't happen.
  • Broken object level authorization (OWASP API Security's #1 risk) is a realistic, common shape for this: an endpoint that fetches a resource by ID with no check that the requester actually owns it. Nothing about that fails a typical happy-path test.
  • Reviewing vibe-coded output doesn't require reading every line. One question, "what happens if this ID belongs to someone else," catches most of this specific failure class in a single pass.

Vibe coding isn't bad. Shipping vibe-coded output without review, on something that isn't disposable, is what actually breaks. Andrej Karpathy coined the term in February 2025 for a specific case: "throwaway weekend projects," work where forgetting the code even exists costs nothing, because nothing depends on it staying correct.

Most of what breaks under the "is vibe coding bad" question isn't vibe coding itself. It's vibe coding applied somewhere its own inventor never scoped it for.

That distinction matters more than it sounds like it should, because it changes the actual question. "Is vibe coding bad" has no single answer. "Is vibe coding bad for this specific piece of code, given who depends on it" does.

What actually breaks

The failures that recur aren't broken features, and they aren't specific to one tool. Whether the agent is Claude Code, Cursor, or something else (see our real-task comparison of the three for where they actually diverge), the pattern is the same: something that generates code nobody reviews is very good at producing output that runs, passes the tests it wrote for itself, and looks correct in a quick glance. What it's bad at, systematically, is negative-space checks: the things that should be rejected, not the things that should work.

Picture a small team vibe-coding an internal admin tool for support staff to look up customer orders. The agent ships an endpoint that takes an order ID and returns the order. It works. Every test passes, because every test checks that a valid order ID returns the right order.

Nobody wrote a test for what happens when a support agent, or anyone else, changes the ID in the URL to a number they don't own.

That gap has a name: broken object level authorization, and it's not a rare or exotic bug. It's the #1-ranked risk in OWASP's API Security Top 10, ahead of every other category, precisely because it's this easy to ship by accident. An endpoint that fetches a resource by ID and never checks whether the requester is allowed to see that specific resource will pass every happy-path test a code-generation agent tends to write for itself.

Why it breaks there specifically

Agents optimize for what they can verify, and what they can verify is whether the code does what it was asked to do. "Fetch the order with this ID" is a request an agent can satisfy and test cleanly. "Fetch the order with this ID, but only if the requester is actually allowed to see it" requires the agent to reason about a case nobody explicitly described, which is exactly the kind of implicit requirement that gets lost between a prompt and its output.

This is the specific thing review catches that testing usually doesn't. A test suite generated alongside the code tends to test the code's own assumptions. A human glancing at the same endpoint and asking "what stops someone from just changing this number" is asking a question the code was never designed to answer, which is precisely why it's the question worth asking.

What changes when someone actually reviews it

Review here doesn't mean reading every generated line, that's not realistic and it's not what closes this gap anyway. It means asking a small number of specific questions before the code ships: does this endpoint check ownership, not just validity, of the thing it's returning? Are there hardcoded credentials anywhere in what the agent just wrote? Does anything here trust a value from the request that it shouldn't?

None of those questions require re-deriving the code from scratch. They require someone who already knows what to look for spending a few minutes looking. That's a meaningfully different cost than writing the feature by hand, and it's the actual tradeoff underneath the "is vibe coding bad" question: not whether to use it, but whether the review step that makes it safe for something real ever actually happens.

A repo-level instruction file won't do that review for you, but it's a reasonable place to put a standing reminder of what to check, alongside whatever convention the team already uses for CLAUDE.md, Cursor rules, or AGENTS.md rather than relying on everyone remembering to ask the same questions from memory.

None of this has to be manual every time, either. A second pass, prompted specifically to look for missing ownership checks rather than to review the code generally, catches a meaningful share of this exact pattern before a person needs to look at all. That won't replace judgment on anything genuinely ambiguous, a case where it's legitimately unclear who should be allowed to see what. But it closes the gap on the mechanical cases, which is most of them.

The honest version of this isn't "vibe coding is dangerous." It's that a technique explicitly scoped for throwaway work doesn't stop being risky just because it got used somewhere that stopped being throwaway.

Sources
Related