← All news
security5 min read

Why AI-generated code is full of security holes (and how to fix them)

By Seaworthy · June 15, 2026

Teal LED panel with glowing circuit lines, suggesting digital security and code infrastructure

Photo by Markus Spiske on Unsplash

The confidence problem

AI coding assistants are genuinely impressive at generating boilerplate. They know the shape of a REST endpoint, a database query, a JWT validation flow. What they are less good at is knowing which parts of that shape are load-bearing from a security standpoint.

The result is code that looks completely reasonable on a quick read. It compiles, it passes basic tests, and then six months later someone discovers that the authentication middleware can be bypassed with a crafted header.

I'm not saying this to be dramatic. I'm saying it because it happened to me, and because the underlying reasons are structural, not accidental.

Why the training data is the problem

Large language models learn from code that already exists on the internet. A meaningful chunk of that code is insecure. Stack Overflow answers from 2012 with hardcoded secrets. GitHub repos where someone committed an .env file and then deleted it (the history is still there). Tutorial blog posts that use eval() on user input because it was the shortest path to a working demo.

The model doesn't know those patterns are dangerous. It knows they appear frequently in contexts where people were trying to solve a problem. So it reproduces them, confidently, without a warning label.

The specific patterns that show up most often in AI-generated code:

  • Secrets in source code. An AI asked to "add a SendGrid integration" will often produce something like const apiKey = "SG.abc123..." directly in the file, because that is what the training examples looked like.
  • SQL concatenation instead of parameterised queries. Writing "SELECT * FROM users WHERE id = " + userId is shorter than the parameterised version, and plenty of training examples do exactly this.
  • Missing authentication checks. An AI that generates a new route often doesn't add auth middleware unless you explicitly ask, because the route itself is the thing being requested.
  • Overly permissive CORS. Access-Control-Allow-Origin: * solves the immediate problem the developer is describing. It also opens the API to cross-site requests from anywhere.

The "it works" trap

Here is what makes this genuinely tricky: the code works. It does what it was asked to do. The security issue is invisible at runtime during normal use, which means it doesn't show up in your tests and doesn't trigger any visible error.

The gap between "code that works" and "code that is safe" is exactly where AI assistants fall down most often. They are optimising for the first thing, not the second.

This is also why code review is unreliable as your only defence. A reviewer who is moving fast, or who is not specifically looking for security issues, will follow the same path as the AI: verify that the logic is correct and move on.

What actually helps

Static analysis on every commit. Not a style linter, actual security-focused analysis that looks for the patterns described above.

If you are running a Node.js or TypeScript project, you can start with something like:

npx seaworthycode scan --category security

This scans for hardcoded secrets, injection vectors, missing auth middleware, and other patterns that show up routinely in AI-generated code. The output tells you which file, which line, and what the risk is.

For a full repo scan across all categories:

npx seaworthycode scan

The categories beyond security (resilience, ops basics, dependency hygiene, configuration, data exposure) matter too, but security is the one where AI assistants create the most concentrated risk.

Beyond static analysis, a few practices that reduce the surface area:

Run a secret scanner in your CI pipeline before anything merges. git-secrets or truffleHog both work. If a key gets committed, the scan catches it before it reaches a shared branch or, worse, a production deploy.

Treat AI-suggested database queries with specific suspicion. When an assistant writes a query, check whether it uses parameterised inputs before you accept the suggestion. This takes five seconds and catches an entire class of SQL injection vulnerabilities.

Don't accept authentication middleware suggestions without checking what they actually verify. A function called requireAuth that checks whether a token exists but doesn't validate its signature is not authentication. It is a false sense of security with a friendly name.

The mindset shift

The mistake is treating AI code generation as equivalent to a senior developer writing code. It isn't. It is closer to copying from a Stack Overflow answer: often correct, occasionally dangerously wrong, and requiring the same critical eye you would apply to anything you didn't write yourself.

The tools that help most are the ones that operate without relying on that critical eye being applied consistently. Automated scanners don't get tired, don't get excited about shipping a feature, and don't assume that something looks fine.

AI-assisted development is faster. It is also a new surface for introducing old vulnerabilities at speed. Those two things are both true, and the second one doesn't cancel out the first, but it does mean you need tooling in place that wasn't necessary before.

Seaworthy is a static analysis tool built specifically for AI-assisted codebases, scanning across security, resilience, ops basics, dependency hygiene, configuration, and data exposure categories.

This article was generated by AI and summarises publicly available sources.

From the makers of Seaworthy

Seaworthy scans your repo for the issues covered in articles like this one.

Security gaps, exposed secrets, and misconfigurations — caught before you deploy. Free to run, no account needed.

$ npx seaworthycode