AI Is Shipping Your Code. Nobody Told It How Attackers Think.

Been doing security research long enough to know that the most dangerous vulnerabilities are never the exotic ones. They’re the boring ones. The ones hiding in plain sight because everyone assumed someone else checked.

April. We’re scanning a live production app. AI-built, real users, active deployment. We find a bootstrap endpoint. Nothing special looking. Except it returns the application’s master authentication token to any caller. No auth. No rate limit. The server’s bound to 0.0.0.0 so any host that can reach the port gets the keys. We’re talking every API key, every database password, every third-party credential the app has ever been handed. Fourteen secrets. One GET request.

Team fixed it same day. Good engineers. Cared about security. Wrote the vulnerability themselves without knowing it — because they were using an AI assistant that had no idea what it was building toward.

That’s the thing nobody is talking about clearly enough yet.

AI Is Brilliant at Code. Terrible at Threat Modeling.

Here’s what AI coding assistants are actually good at: satisfying a prompt. You say “build me an auth system,” you get an auth system. Tests pass. Frontend works. Looks right.

What the model cannot do is think like an attacker. It has no threat model. It has never been on the receiving end of a SQL injection or watched someone chain a Pydantic field-drop into a full platform takeover. It has been trained on code that works and optimized to produce more code that works. Security was never in the objective function.

So it does what language models do, reproduces patterns from training data. The safe patterns and the dangerous ones, with equal confidence, because nothing in training ever told it which was which.

Georgetown’s CSET measured this. 2.74x more vulnerabilities in AI-generated code versus hand-written. Nearly three times. And you’re shipping it faster than ever before.

Meanwhile on the attacker side the math has also changed. CVE to working exploit used to take weeks of skilled work. With an LLM it takes under an hour. The cost to develop a targeted attack against a specific application has dropped 100x. Your surface area is expanding daily. Their capability is too.

The Patterns We Keep Finding

We’ve scanned a lot of AI-built codebases this year. The vulnerabilities are not random. They show up in the same places, the same ways, over and over. Because AI makes the same category of mistakes consistently.

The edges nobody thought about. AI assistants implement what you ask for. Ask for auth, you get auth, for the flows you described. What you don’t get is someone thinking about the bootstrap endpoint, the initialization route, the admin API that got scaffolded at 2am and forgotten. These surfaces exist outside the prompt so the model never worried about them. We find exposed credential endpoints, admin interfaces on 0.0.0.0, health check routes returning internal state. The Cognithor case above is one of a dozen variations on this exact pattern this year alone.

Authorization that disappears in transit. This one we see constantly and it’s the most insidious because the code looks right at every layer. Take LiteLLM — thousands of deployments, proxy layer for LLM API access. An org admin could hit POST /user/bulkupdate and escalate any user on the entire platform to proxyadmin in a single request. The auth check read organization_id from the request body and confirmed it. Then handed the payload to a Pydantic model that didn’t declare that field. Pydantic silently dropped it. The handler that did the actual DB write never saw the constraint.

Three pieces of code, all individually correct. The vulnerability lives in the interaction between them. AI thinks in functions. It doesn’t model what happens to a value as it transits framework layers, gets deserialized, hits an ORM. That cross-layer systems thinking is exactly where it falls down.




Dangerous defaults reproduced at scale. VibeVoice by Microsoft. Checkpoint loading script calls torch.load() without weights_only=True. PyTorch’s default pickle deserialization executes arbitrary Python during unpickling — this is documented, known, the safe flag has existed since PyTorch 1.13. The AI didn’t use it because most torch.load() in its training data doesn’t use it. Unsafe was the common pattern. Common patterns are what language models reach for.

A crafted .pt file passed to this script runs attacker code before any application logic. In CI that means the runner’s token, every repo secret, internal network access — exfiltrated silently during what looks like a normal job. Microsoft acknowledged and patched same week.

This pattern is everywhere. requests.get() on user-supplied URLs with no validation. yaml.load() instead of yaml.safe_load(). subprocess built from input that looked controlled in the prompt. The safe and unsafe versions look nearly identical. The model has no preference.

The right tool was already there. Ghost CMS had a hardened HTTP client that blocked RFC-1918 ranges and prevented DNS rebinding. Used it everywhere – oEmbed fetches, webmentions, recommendations. The webhook delivery path used the unprotected client. One import, different library. The security investment had already been made. The fix was already in the codebase. It just didn’t get picked up on that path.

This is probably the most common failure mode we see and the hardest to catch manually because nothing looks wrong in isolation. You only see it when you trace execution paths across files – who calls what, which HTTP client ends up on the wire. AI doesn’t do that analysis when it writes code. Neither does anyone in code review.

The Old Security Playbook Was Not Built for This

Quarterly pentest: $15k, findings delivered two weeks after the snapshot was taken, half of it already shipped past. Good for compliance. Bad for a team shipping daily.

One security hire against ten engineers with AI assistants is not a security program. It’s a speed bump with a salary.

Static scanners: the findings above would pass most of them. They were built for hand-written code patterns. The cross-layer authorization failure, the missing safe flag, the wrong HTTP client — these don’t match what static analysis was trained to flag. Teams stop reading scanner output within weeks because the noise-to-signal ratio makes it useless. The three findings that matter are under three hundred warnings nobody has time to investigate.

None of these move at the speed you’re actually shipping.

What moderns solutions exist and how effective are they?

Kira connects to your repo — GitHub, GitLab, Bitbucket, one click — and runs on every push. Traces data flow across your entire codebase, not file by file. Follows values across function calls, module boundaries, framework layers. Looking for the places where something untrusted ends up somewhere it shouldn’t, where a constraint put in at one layer doesn’t survive to the next.

When it finds something it doesn’t suggest you investigate. It shows you whether it’s actually exploitable. Proof of concept. Reproduction steps. Something you can run yourself before you decide whether to care.

Findings come out as reports you can share, with a customer asking about security posture, an auditor, an investor. Clean enough to hand over, detailed enough to act on.

The cases above came from Kira. Cognithor, LiteLLM, Microsoft, Redash, Ghost – all of them. The teams in every one of these cases fixed it within a day or a week. Security-conscious people who simply hadn’t had anyone look yet.

Connect your repo and find out what’s actually in there.


One More Thing

The teams whose code is in this post are not examples of bad engineering. They are examples of what happens when you build fast with AI assistance and don’t have something scanning the output. Which is most teams right now.

The vulnerability your AI wrote today probably isn’t catastrophic on its own. It’s the one that chains with something else. An exposed endpoint plus a predictable token format plus a service running with too many permissions. None of those are disasters individually. Together they are.

Run the scan. See what’s there for free.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.