Notes

Why SAST Can't Keep Up with the Prompt-to-PR Loop

SAST finds known-bad patterns. AI-generated code fails by omission — missing auth checks, missing tenant isolation, missing rate limits. Those gaps don't show up in a scan queue. They show up in incident reports.

AI generated code security

A developer opens Cursor. Pastes a Jira ticket. Gets 300 lines of scaffold code. Reviews it. Pushes to main in 20 minutes.

SAST picks it up on the next scheduled scan. Which runs tonight.

Meanwhile, that code is already in staging.

SAST Was Built for a Different Bottleneck

When SAST tools were designed, the security team's problem was keeping up with human-authored code. Developers wrote maybe 50–100 meaningful lines of production logic a day. The scan queue had a fighting chance.

The prompt-to-PR loop broke that math. A developer with a capable AI coding agent can go from spec to merged PR in under 30 minutes. A team of 40 engineers running parallel AI sessions can ship in a single sprint what used to take a quarter. JetBrains' 2025 State of Developer Ecosystem survey found 78% of developers now use AI coding tools daily.

The queue doesn't break dramatically. It just quietly becomes irrelevant. Your SAST tool is scanning last week's code while this week's code is already serving traffic.

But velocity is actually the smaller problem.


SAST Finds Patterns. AI-Generated Code Fails by Omission.

This is the one most teams are still figuring out, so let me be specific.

SAST is a pattern-matching engine. It looks for known-bad code signatures: SQL string interpolation on user-controlled input, hardcoded credentials, insecure cryptographic primitives, common injection sinks. These are things that were written wrong.

AI-generated code fails differently. It fails by leaving things out.

A developer prompts "add an endpoint to fetch user orders by ID." The model writes code that compiles, passes a smoke test, and looks fine in a diff review. It may also be missing:

  • Tenant isolation (it fetches by order ID, not by user_id = authenticated_user)
  • Rate limiting on the endpoint
  • Authorization dependency injection — the model assumed auth happens in middleware, the middleware doesn't exist
  • Input validation on the ID parameter before it hits the ORM

None of those are wrong patterns. They're absent controls. And absent controls have no signature for SAST to match.

You cannot regex-search for a missing if.

Veracode's 2025 GenAI Code Security Report found 45% of AI-generated code contains at least one OWASP Top 10 vulnerability. Sherlock Forensics put the number at 92% for fully AI-generated features — not individual functions, but complete features built by a coding agent without threat-informed guardrails. The gap between those two numbers tells you something. As AI writes more of the feature, the vulnerability profile shifts from wrong patterns to missing architecture.

SAST was built for the 45%. It has almost nothing to say about the 92%.


The Model Doesn't Know Your Threat Model

Here's the thing nobody wants to say plainly: when your engineer prompts an AI coding agent to build a feature, the model has no idea where your trust boundaries sit.

It doesn't know which inputs are attacker-controlled. It doesn't know what "authenticated user" means in your specific auth layer. It doesn't know whether your multi-tenant database uses row-level security or application-level filtering. It generates from training patterns and from whatever made it into the prompt.

If your engineer didn't describe the threat model in the prompt, the model didn't apply one.

This creates a category of vulnerability that isn't a code bug. It's a design decision — the model made an implicit assumption about trust that doesn't match your architecture, and the implicit assumption shipped to production. These are business logic flaws. Broken object-level authorization. Privilege escalation paths that exist because the model defaulted to a permissive pattern when the threat model wasn't specified.

DAST catches some of these — if you can model the attack surface and write the test. But DAST also runs downstream, after deployment, and most teams are not writing comprehensive auth and authorization test suites against AI-generated endpoints as fast as those endpoints are being generated.

The pattern I see consistently in AI-assisted codebases, from the security reviews my team at we45 runs:

  • Overly permissive object references — the model didn't know to scope queries to the authenticated principal
  • Infrastructure-as-code defaults — Terraform and CloudFormation generated from prompts where the model chose * resource policies because least privilege wasn't specified
  • Hardcoded fallback credentials in generated configuration code — not the primary credential, the fallback that nobody noticed
  • Absent logging on AI-scaffolded endpoints — not a compliance miss, an incident response miss

These patterns have one thing in common: they aren't in the SAST ruleset. They require knowing what controls should be there for a given endpoint — and checking whether they were included.
Where SAST Ends and the Real Problem Begins

To be clear about what I'm not saying: SAST isn't useless. Pattern-matching on known-bad signatures has real value. Catching an obvious SQL injection before it ships is better than not catching it.


But SAST was designed as the last line of defense for code that a human threat-modeled, however informally, while writing it. The developer who wrote that auth flow knew this endpoint was public. They may still have gotten it wrong — but there was a human threat model in the room.

AI-generated code has no implicit threat model. The security judgment has to come from somewhere else, because it is not in the model's training data and it is not in the default prompt.

The somewhere else has to be upstream. Before the code is written.

That means threat-informed rules — specific to your architecture, your trust model, your attack surface — present in the coding environment, on every prompt, before the output is generated. SQL parameterization, authenticated user scoping, tenant row filters: enforced at write time. Not discovered in a scan queue.

And when the PR does land, review that's aware of what controls should be present for that endpoint — not just what patterns look wrong in the diff.


Security at Write Time, Not Scan Time

This is what VibeReview was built to solve.

The root problem is a security architecture design gap: your threat model lives in a Confluence page or a threat modeling session from last quarter, completely disconnected from the environment where code is actually being written. The AI coding agent has no access to it. So it generates without it.

VibeReview closes that gap. We read your repo for entry points, trust boundaries, where user input lands, and the AI coding patterns most likely to go wrong in your specific stack. The output is a security architecture design expressed as threat-informed guardrails — do/don't rules mapped to OWASP Top 10 and the Cisco AI Security Taxonomy, traced to real threats in your codebase, not generic checklists. Those rules ride into Claude Code, Cursor, Codex, and Copilot via MCP, present on every prompt.

Your developers don't change their workflow. The threat model rides with them.

When a PR lands, VibeReview reviews the diff against the same threat-informed rules and comments only on lines that crossed one — with the rule name and a one-line mitigation. No 40-comment storms. No noise. Just the things that matter, where they happened.

SAST catches code written wrong. VibeReview enforces the controls that AI-generated code tends to leave out.

The prompt-to-PR loop is not going to slow down. The security function has to move upstream to match it — or keep running a scan queue that's perpetually a sprint behind.



See what VibeReview finds in your repo. Start a free 14-day trial → No card required.

Stop reviewing AI code by hand.

Set up VibeReview in your IDE in five minutes.

Start free trial