Eighty-seven percent. That’s the share of AI agent pull requests that contain at least one security vulnerability, according to DryRun Security’s March 2026 Agentic Coding Security Report. If you’re merging AI-generated code without a structured security review, the odds are not in your favor.
The uncomfortable truth about AI coding agent security vulnerabilities is that they aren’t random noise — they’re predictable. DryRun tested Claude Code, OpenAI Codex, and Google Gemini across two real applications and found the same vulnerability categories appearing in every agent, every time: 143 security issues across 38 scans. Not one of the three agents produced a fully secure application.
This post names the five most dangerous patterns — the ones your existing scanner will miss — and gives you a checklist to run against every AI-generated PR before it reaches production.
Why AI Agents Keep Making the Same Security Mistakes (It’s Not a Bug, It’s a Pattern)
The repetition isn’t coincidental. It has a structural cause.
AI coding models are trained to produce code that works — code that compiles, passes tests, and satisfies the stated requirement. They optimize for syntactic correctness. What they don’t optimize for is semantic trust-boundary enforcement: the question of whether your application correctly distinguishes between what a user is allowed to do and what they’re merely asking to do.
Every vulnerability pattern in this post flows from that single architectural blind spot.
“AI models treat ‘working code’ and ‘secure code’ as the same thing. They are not.”
The scale of the problem is accelerating fast. By June 2025, AI-generated code was introducing over 10,000 new security findings per month — a 10× spike from December 2024 — with privilege escalation paths up 322% and architectural design flaws up 153% (Apiiro, 2025). AI-generated pull requests average 10.83 issues each versus 6.45 in human-written PRs — roughly 1.7× more defects per PR (CodeRabbit, 2025).
And 85% of developers are already using these tools regularly (JetBrains Developer Survey, October 2025). The math is unambiguous: the risk is compounding across every team, every sprint.
What makes DryRun’s findings especially valuable is the pattern fidelity. Across three different agents and two different applications, ten vulnerability categories appeared consistently enough to be treated as structural signatures — not coincidences. Five of them are particularly dangerous, not just because they’re severe, but because most traditional SAST tools cannot detect them. Understanding why each recurs is what lets you spot variants you haven’t seen before.
Blind Spot #1 — Broken Access Control: The Unauthenticated Endpoint Problem
This is the most universal finding in the entire report. Every agent. Every application.
AI agents create unauthenticated endpoints on sensitive and destructive operations with striking consistency. They build the handler. They write the route. They don’t attach the authentication middleware to it.
The failure pattern typically looks like this: the agent correctly implements authentication for standard read paths and GET requests. Then, for a destructive admin action or a write operation added later in the session, it generates a new route without importing the auth middleware that was already established elsewhere. The code works. The tests pass. The endpoint is open to anyone with an internet connection.
This isn’t carelessness — it’s a context problem. As a codebase grows across a multi-PR development cycle, the model loses reliable access to the full middleware map. It generates locally correct code that is globally broken.
What to check in every PR:
- New routes that don’t explicitly reference auth middleware — not assumed by inheritance
- Admin or destructive endpoints (DELETE, state-changing PUT) without middleware applied and confirmed
- Any route added in a new file that doesn’t import from your established auth module
Blind Spot #2 — Business Logic Failures: When the AI Trusts the Client
Here’s where AI-generated code diverges most sharply from secure-by-default human code.
Business logic failures occur when your application accepts values from the client that should only ever be computed server-side. Scores, account balances, unlock states, price overrides — things that directly affect application behavior and, often, money or data integrity.
Every tested codebase in the DryRun report exhibited this pattern. The model builds a feature that updates a game score, a subscription tier, or a reward balance — and it accepts that value directly from the request body. The server-side calculation is either absent or bypassed entirely.
Why does this happen? The AI is modeling what the developer described. “Update the user’s score” gets implemented as an update. The prompt never said “calculate the score server-side and reject client-supplied values,” so that constraint never makes it into the code.
AI-generated code is 1.91× more likely to make insecure object references than human-written code (CodeRabbit, 2025). That statistic lives exactly in this pattern.
What to check in every PR:
- Request handlers that accept user-controlled values for state that should be computed — scores, balances, tiers, unlock flags, permissions
- Missing server-side validation before writing user-supplied data to the database
- Any `req.body` value flowing directly into a database write without transformation or server-side verification
Blind Spot #3 — OAuth Misimplementation: Every Social Login Is Broken the Same Way
This one stings because OAuth looks correct in AI-generated code — until you check the state parameter.
All three AI agents in the DryRun study omitted CSRF state parameters in every OAuth flow they built. They also consistently implemented insecure account-linking flows — connecting a social provider identity to an existing account without first verifying ownership of that account.
The CSRF state parameter exists specifically to prevent cross-site request forgery attacks against your OAuth callback. Without it, an attacker can trick a user into completing an OAuth flow that links the attacker’s social account to the victim’s application account — a complete account takeover vector delivered inside a feature that looks like it’s working correctly.
This is a training data problem. OAuth examples in the wild frequently omit the state parameter because developers copy-paste working flows that skip this step. The model has seen thousands of examples without it. It reproduces the pattern faithfully.
Every social login an AI agent builds for you is structurally vulnerable to the same two attacks unless you manually add the state parameter and fix the account-linking logic.
What to check in every PR:
- OAuth callback handlers that don’t validate a `state` parameter against a server-side session value
- Account-linking flows that accept a provider token without verifying the current user owns the target account
- OAuth library configuration files — check that the `state` parameter is explicitly set, not left to default or omitted
Blind Spot #4 — WebSocket Authentication Gaps: The Middleware That Goes Nowhere
This is the most architecturally subtle of the five patterns, and arguably the most dangerous because it’s structurally invisible to most reviewers.
Here’s what happens: the AI agent correctly wires authentication middleware to your HTTP routes. The REST API is protected. Then you ask it to add real-time features via WebSocket. The agent generates a WebSocket handler — but it never applies the authentication middleware to the WebSocket upgrade request.
The result is a persistent, unauthenticated channel running alongside your properly secured REST API. WebSocket authentication was missing from every final game codebase across all three tested agents, despite correct REST middleware being present (DryRun Security, March 2026).
The structural reason: REST middleware wiring is thoroughly represented in training data. WebSocket upgrade handlers requiring separate, explicit authentication logic are not. The model has a strong, well-reinforced pattern for `app.use(authMiddleware)` and a weak, underrepresented one for `wss.on(‘connection’, (ws, req) => { / authenticate req here before proceeding / })`.
Once the upgrade handshake completes, the connection is persistent. Any command accepted over it is accepted from whoever reached that endpoint — authenticated or not — for the life of the session.
What to check in every PR:
- WebSocket upgrade handlers that don’t authenticate the request before accepting the connection
- `wss.on(‘connection’)` or equivalent event handlers that don’t reference your auth module
- Server-sent event endpoints that apply different — or absent — auth logic compared to your REST routes
Blind Spot #5 — Rate Limiting Disconnects and Client-Side Trust: Defined, Never Wired
Rate limiting middleware was defined in every AI-built codebase tested. No agent ever wired it to the application (DryRun Security, March 2026).
Every. Single. One.
This is the most quietly damaging pattern in the set because it manufactures false confidence. The code review shows rate limiting middleware present. The module is imported. You might even see it referenced in a configuration block.
But if it’s never mounted with `app.use()` or equivalent — if it’s never placed in the actual request pipeline — it does nothing at all. The code is inert.
The same composition failure applies to client-side trust more broadly. The AI generates validation logic. It places that logic on the wrong side of the trust boundary. Or it defines the function but never calls it in the right context.
The validation exists in the file. It never runs.
This is a wiring problem, not a component problem. AI agents generate components correctly in isolation, then fail to compose them into a system that is secure as a whole. The pieces are present. The architecture is broken.
What to check in every PR:
- Every imported middleware module — confirm it appears in `app.use()` or the routing chain, not just in `require()` or `import` statements
- Validation functions — confirm they are called before sensitive operations, not merely defined somewhere in scope
- A quick search for defined-but-never-used security modules: `const rateLimiter = require(…)` or equivalent with no downstream invocation
Why Your Current Security Tools Won’t Catch These (And What Will)
Here’s the uncomfortable part for teams relying on SAST scanners.
Traditional static analysis tools work by pattern matching — they search for known dangerous constructs: SQL string concatenation, unsanitized output in HTML context, `eval` with user input. They are excellent at exactly that job. They don’t do what you need here.
None of the five patterns above are regex-detectable. Catching them requires a different class of analysis:
- Middleware trace analysis: Can the tool follow whether a defined middleware module is actually mounted in the request chain?
- Data flow through trust boundaries: Can it determine whether a value from `req.body` reaches a database write without server-side computation?
- WebSocket vs. HTTP auth equivalence checking: Can it verify that auth logic applied to REST routes is also applied to WebSocket upgrade handlers?
- Cross-file control flow: Can it trace whether a validation function defined in `validators.js` is actually invoked in `routes.js`?
For most SAST tools, the answer is no to all four. These are logic-level, flow-tracing vulnerabilities — they require contextual, semantic analysis across the full codebase, not line-by-line pattern matching.
One more critical point that most teams miss: scanning only the final build understates your risk significantly. Vulnerability patterns compound across PRs. A broken authentication pattern introduced in PR #3 can make a technically sound PR #7 dangerous. PR-level scanning throughout the development cycle catches what final-build-only scanning will always miss.
The Veracode 2025 GenAI Code Security Report found that GenAI introduces security vulnerabilities in 45% of cases across 100+ LLMs on 80 real-world coding tasks. That risk doesn’t appear only at the end — it accumulates incrementally.
AI Coding Agent Security Vulnerabilities: 15-Point Pre-Merge Checklist
Run these before merging any AI-generated PR. They’re keyed directly to the five patterns above.
Access control (Blind Spot #1)
- Every new route explicitly references auth middleware — not inherited by assumption from a parent file
- Admin and destructive endpoints (DELETE, state-changing PUT) are authenticated — confirmed, not assumed
- New route files import the established auth module, not a reimplemented local version
Business logic (Blind Spot #2)
- No `req.body` value flows directly into a database write without server-side calculation or transformation
- Score, balance, tier, and permission values are computed server-side — never accepted directly from the client
- Object reference checks include ownership verification, not just existence checks
OAuth (Blind Spot #3)
- OAuth callback handlers validate a `state` parameter against a server-side session value before processing the response
- Account-linking flows verify current-user ownership before connecting a new provider identity
- OAuth library configuration explicitly sets the `state` parameter — it is not left to default or omitted
WebSocket authentication (Blind Spot #4)
- WebSocket upgrade handlers authenticate the request before accepting the connection — not after
- `wss.on(‘connection’)` or equivalent handlers reference your auth module explicitly
- Real-time endpoints apply equivalent auth logic to your REST routes — not lighter logic, not none
Rate limiting and middleware wiring (Blind Spot #5)
- Every imported middleware module appears in `app.use()` or the routing chain — not just in import statements
- Validation functions are called before sensitive operations — search for defined-but-never-invoked validators
- No security modules exist only as `require()` / `import` statements with no downstream reference in the request pipeline
Conclusion
AI coding agent security vulnerabilities follow five predictable patterns — broken access control, business logic failures, OAuth misimplementation, WebSocket auth gaps, and disconnected middleware. They recur because AI models optimize for code that works, not code that enforces trust boundaries. And they’ll pass your functional tests every single time.
The five-pattern framework gives you a mental model for spotting variants you haven’t encountered before, not just the specific examples in this post. The checklist gives you something concrete to run today.
Start with the 15 checks above on your next AI-generated PR. If any of them surface a finding, consider making the checklist a formal part of your team’s review process — and evaluate contextual security analysis tools that can trace middleware wiring and data flows automatically rather than relying on pattern-matching scanners alone.
Your AI tools ship fast. Make sure your security review keeps pace.