2026-08-04 · 14 min read · The Defen.so team

Security governance for vibe-coded software

A year ago, writing code was the slow part. You'd stare at a blank file, reach for docs, wire the plumbing by hand. Security fit into that rhythm: the same person who wrote the query knew it was a query, and knew it needed a parameter binding.

Vibe coding broke that rhythm in the best possible way. The code appears. A whole authentication flow, a payment webhook, a file-upload endpoint, generated in the time it used to take to name the function. The bottleneck moved. It is no longer writing the code. It is governing it, knowing what shipped, whether it's safe, and how to keep it safe as five more features land on top of it this week.

This is a governance model for that world. Not a checklist you run once and forget, a system that keeps AI-generated software honest as it grows. We'll cover the four layers that matter, why heuristics do most of the heavy lifting, where AI review genuinely helps and where it quietly wastes your time, and how to keep a team from drifting back into "we'll add security later."

The core problem: the generator doesn't know your threat model

A language model writes the most probable code for your prompt. Probable is not the same as safe. If ten thousand tutorials concatenated user input into a SQL string, the model learned that pattern too, and it will happily reproduce it when the surrounding context looks tutorial-shaped.

It's not that the model can't write secure code. Ask it directly to parameterize a query and it will. The problem is that you have to know to ask, on every endpoint, every time, forever. That doesn't scale, and it definitely doesn't survive being handed to a teammate who prompts differently than you do.

Governance is what replaces "remember to ask." It makes the safe path the default path, catches the unsafe path automatically, and gives you a clear picture of what's actually running. Four layers do this.

Layer 1 — Guardrails you commit to the repo

The cheapest, most durable control is a file the AI reads before it writes. A CLAUDE.md, a .cursorrules, an agent instruction file, whatever your tool uses. It sits in the repo, it's version controlled, and every prompt inherits it.

The mistake people make is filling it with vague virtue ("write secure code"). The model already thinks it does. Guardrails work when they're specific and mechanical:

# Security rules (non-negotiable)
- Never build SQL by string concatenation. Use parameterized
  queries / the ORM's binding, always.
- Never read secrets from literals. Read from env; if a value
  isn't in env, stop and ask.
- Every new POST/PUT/DELETE route gets input validation before
  it touches the database.
- Auth-adjacent routes (login, reset, verify) get a rate limit.
- No secret, key, or token in any file under a public/ or
  client-bundled directory.

These read like the output of a linter because that's the point. A guardrail that a machine could check is a guardrail the model can follow. The vague ones get ignored; the mechanical ones get obeyed.

This layer is free and it moves the baseline more than anything else on this page. But it's advisory. The model usually follows it. Governance can't rest on "usually," which is why there are three more layers.

Layer 2 — Heuristics that catch the known-bad, fast

Here's the load-bearing claim of this whole piece: for the problems that actually sink vibe-coded apps, a boring heuristic beats a clever model.

The failures we see most are not subtle. An .env committed to git. A hardcoded sk_live_ key in source. A Firebase project with allow read, write: if true. Supabase RLS left off. A dependency that's three majors behind and sitting on a published CVE. Every one of these is a pattern, and patterns are exactly what a regex, a version comparison, or a lookup against a vulnerability database catches instantly and explains completely.

The trade-off is real and it's worth stating plainly:

Property Heuristic checks AI review
PrecisionHigh, a hit is almost always realVariable, hedges and hallucinates
RecallLower, only finds what it knowsHigher, generalizes to novel bugs
ExplainabilityTotal, names the file, line, and ruleLower, "looks suspicious"
Speed & costMilliseconds, near-zero costSeconds, per-token cost
Best atSecrets, config, known CVEs, styleLogic flaws, semantic bugs

A developer who gets a false positive twice stops reading the tool. High precision is not a nice-to-have; it's what keeps the tool in the workflow at all. So the governance rule is: use heuristics for everything they can cover, and reach for AI only for the class of problem heuristics structurally cannot see.

Concretely, a heuristic pass over a repo should catch, with a named file and line for each:

None of that needs a model. All of it is deterministic, instant, and explainable, which means a developer can trust it, act on it, and not resent it.

Layer 3 — AI review, used narrowly and on purpose

AI review earns its keep on exactly the thing heuristics miss: meaning. A regex can't tell you that an authorization check reads the user ID from the request body instead of the session, so any user can act as any other. It can't see that a "delete old records" job has an off-by-one that nukes the newest ones. Those are semantic, and semantics is where a model generalizes past its training in a way pattern-matching never will.

The governance discipline here is to scope it tightly, because unscoped AI review is where the cost and the noise come from:

The right mental model is a two-pass funnel. Heuristics run first and clear the known-bad cheaply and precisely. AI runs second, on a much smaller surface, looking only for the semantic problems the first pass can't represent. You get the precision of the heuristic and the reach of the model without paying for either everywhere.

Layer 4 — Runtime, because static analysis can't see traffic

Everything so far reads code. But some of what governs a live app only exists at runtime: who's actually hitting your login route, whether the request carrying a SQL payload is getting through, whether the site is even up. No amount of source review tells you an attacker is probing /.env right now.

Runtime governance is three things running continuously:

The design principle for runtime controls in a vibe-coded stack is fail open. If the protection layer has an incident, the app keeps serving traffic. You lose coverage for the duration of the outage; you never lose availability. Security that can take your product down is a security tool you'll eventually rip out.

Putting it together: what a governed pipeline looks like

None of these layers is exotic. The governance is in wiring them so the safe path is the path of least resistance:

Notice the shape: heuristics carry the volume, AI carries the nuance, runtime carries what code review can never see. Each layer covers the previous layer's blind spot, and none of them depends on a human remembering to be careful.

The failure mode to watch for: drift

The way governance dies is not a dramatic breach. It's drift. A rule gets added to the guardrail file and then contradicted in a prompt three weeks later. A scan starts throwing a false positive, someone mutes the whole category instead of tuning the one rule, and now real findings hide in the muted pile. A "temporary" hardcoded key becomes permanent because it works and nobody re-reads that file.

The countermeasures are unglamorous and they're the whole game:

Where this leaves you

Vibe coding didn't make security harder. It made it faster to skip, because the friction that used to force a pause, hand-writing the code, is gone. Governance puts a small, automatic amount of that friction back in exactly the places it matters, and nowhere else.

Commit the guardrails. Let a heuristic scan carry the known-bad, precisely and cheaply. Point AI at the diff for the semantic problems, and make it prove its own findings. Put a fail-open WAF and a monitor in front of the running app. Then let a schedule, not your memory, keep it all honest.

The AI wrote the code. It didn't govern it. That part is still yours, and the good news is that almost all of it can be automated by tools that are fast, precise, and boring, which is exactly what you want standing between a weekend project and the open internet.

Related reading