Blog

Is AI-Generated Code Safe? The Security Risks Explained

AI writes code fast — and often insecurely. The real security risks of AI-generated code, from insecure defaults to hallucinated dependencies, and how to detect them.

Bruno Baldo·Aug 31, 2026·10 min read·Reviewed by Rainforest Technologies

AI coding assistants have quietly become the fastest developers on your team. They autocomplete functions, scaffold entire services, and answer "how do I do X" in the editor without a context switch. The productivity gains are real, and they are not going away. But speed is only half the story. The uncomfortable truth is that a lot of AI-generated code ships insecure — and understanding the security risks of AI-generated code is now a core part of doing AppSec well.

This is not a hype problem or a hypothetical one. Multiple studies have found that a substantial share — frequently cited in the range of 40–50% — of AI-generated code samples contain at least one security weakness. Whether the real number is a bit higher or lower in your codebase almost doesn't matter. The point is that "the machine wrote it" is not a safety guarantee, and treating generated code as trusted-by-default is how vulnerabilities slip into production at a scale manual review was never designed to handle.

So let's answer the question plainly. Is AI-generated code safe? Sometimes. Often enough it isn't. And the difference between the two comes down to whether you have a security layer that inspects it before it ships. Below are the risk categories that matter most, each with a concrete example and the class of tooling that catches it.

Insecure-by-default patterns

The most common category of AI-generated code vulnerabilities is also the most mundane: code that works, passes a quick eyeball test, and quietly omits a security control. Language models are trained to produce plausible, functional code. They are not trained to produce safe code, and "functional" and "safe" are not the same thing.

Ask an assistant for a search endpoint and you may get a SQL query built with string concatenation — a textbook injection flaw — because that pattern appears constantly in training data. Ask for a function that renders user input to a page and you may get output with no encoding, opening the door to cross-site scripting. Ask for password hashing and you might get MD5 or a bare SHA-256 with no salt, because those snippets are everywhere online even though they've been unacceptable for years.

None of these look wrong at a glance. The endpoint returns results. The page renders. The password "hashes." The missing piece is the security control — parameterized queries, output encoding, a modern key-derivation function — and the model has no incentive to add it unless you explicitly ask.

This is exactly what static application security testing (SAST) is built to catch. SAST reads the code, understands data flow from untrusted sources to sensitive sinks, and flags the injection, the unencoded output, the weak crypto — no matter who typed it. When AI is generating a large share of your commits, SAST stops being a nice-to-have and becomes the tripwire that catches the patterns your developers didn't write and may not have read closely.

Hallucinated and non-existent dependencies

Here's a failure mode that has no equivalent in human-written code: the model invents a package that doesn't exist. You ask for a helper to parse some format, and the assistant confidently writes import supersecure-parser and calls functions from it. The library is plausible. The API looks reasonable. It's also entirely fictional.

On its own, a hallucinated import just breaks the build. The real danger is what attackers do with the pattern. It's called slopsquatting: adversaries watch for the package names that models commonly hallucinate, then register those exact names in public registries and fill them with malicious code. The next developer whose assistant hallucinates the same name — and models hallucinate the same names with unsettling consistency — installs a real package that a real attacker controls. Now you have a supply-chain compromise that started as an autocomplete.

The defense is software composition analysis (SCA) paired with a hard rule that every dependency is verified before it lands: does the package exist, who publishes it, how old is it, how widely used, does it carry known vulnerabilities? An SCA layer that inventories every dependency and checks it against reality catches both the hallucinated import and the genuinely malicious one squatting in its place — before it reaches a developer's machine or your build servers.

Inherited vulnerabilities from training data

An AI assistant is a mirror of the code it was trained on, and a lot of that code is old, outdated, or was insecure to begin with. When a model reproduces a pattern that was standard practice five or ten years ago, it inherits the vulnerabilities that came with that pattern.

You see this when an assistant reaches for a deprecated cryptographic algorithm, pins an outdated library version with known CVEs, disables TLS certificate verification "to make it work," or reproduces an authentication flow that predates current best practice. The code isn't malicious and it isn't hallucinated — it's just stuck in the past, faithfully reproducing yesterday's mistakes because yesterday's mistakes were well represented in the training set.

This is a blend of a SAST and an SCA problem. Insecure configuration and deprecated primitives show up in static analysis; outdated and vulnerable dependency versions show up in composition analysis. The common thread is that you cannot rely on the model to know what "current" means. It has a training cutoff and no awareness of the CVE published last week. Your pipeline has to supply that awareness for it.

Secrets and sensitive data in generated code

Ask a model for a working example and it will give you a working example — which sometimes means it fills in the blanks with a hardcoded credential. Generated code has a habit of embedding placeholder API keys, connection strings with inline passwords, or tokens that look like scaffolding but get committed verbatim because "I'll fix it later" is a lie every codebase tells.

There's a second, subtler version of this problem. When developers paste real code — including real secrets — into an assistant to get help, and then paste the response back, credentials can get shuffled around, duplicated, or left in a comment. The generated output looks clean, but a live secret rode along.

Secret scanning is the control here, and it needs to run on every commit, ideally pre-commit and again in CI. A scanner that recognizes credential formats and high-entropy strings catches the hardcoded key before it's pushed — and, just as importantly, tells you when a real secret has already leaked so you can rotate it instead of hoping nobody noticed. With AI in the loop generating boilerplate at volume, the surface area for an accidental credential grows, and manual code review is the wrong tool to catch a 40-character token buried in a config block.

The "no provenance, no owner" problem

Step back from the individual bugs and there's a structural risk underneath all of them: nobody wrote this code, so nobody really owns it. When a human writes a function, they carry a mental model of what it does, why it's shaped that way, and where the sharp edges are. When an assistant generates it and a developer accepts it, that mental model is thin or absent. The author of record is a person who, in practice, reviewed the output for about as long as it took to hit Tab.

This matters for security because review is where a lot of vulnerabilities are supposed to die. "Who reviews code no human wrote?" is not a rhetorical question — it's an operational gap. Provenance is missing: you often can't tell from a diff which lines came from a person and which came from a model, so you can't even target extra scrutiny at the higher-risk material. Accountability is diffuse: when a generated snippet turns out to be vulnerable, there's no author who understood it well enough to have caught the flaw.

You can't solve an ownership gap with a policy memo. You solve it by making the pipeline itself the backstop — an automated security layer that treats every change as untrusted and inspects it on the merits, so that safety doesn't depend on whether a human deeply understood the lines they approved.

Why traditional review misses it

If your answer to AI-generated code is "we review everything anyway," it's worth being honest about why that's cracking under the load.

The first problem is volume. AI assistants don't just help developers type faster; they change the unit of work from a line to a block. A single accepted suggestion can be dozens of lines. Multiply that across a team and the amount of code flowing into review per day climbs far past what careful human reading can keep up with. Reviewers triage. They skim. Security details are exactly the kind of thing that gets skimmed past.

The second is velocity. The whole point of an AI assistant is to compress the time from idea to commit. That compression squeezes the review window too. Pressure to keep pace with AI-accelerated development turns thorough review into rubber-stamping, and rubber-stamping is indistinguishable from no review at all where security is concerned.

The third, and most insidious, is automation bias — the well-documented human tendency to trust output that comes from a machine more than we'd trust the same output from a person. Code from an AI assistant looks authoritative. It's syntactically clean, confidently formatted, and it runs. Reviewers extend it a benefit of the doubt they'd never extend to a hurried pull request from a colleague, precisely when they should be more skeptical, not less.

Put those three together and manual review, on its own, is structurally unable to be the security control for AI-generated code. It's still valuable for design, correctness, and maintainability. It is not a reliable filter for injection flaws, weak crypto, or a leaked token at AI scale. That job needs to be automated, consistent, and applied to every change without exception.

How to get ahead of it

The takeaway is not "stop using AI assistants." That ship has sailed, and the productivity is worth having. The takeaway is that AI-generated code needs the same security scrutiny as any untrusted input — applied automatically, in the pipeline, on every commit.

Concretely, that means SAST catching insecure patterns as they're introduced, SCA verifying every dependency (including the ones that don't exist), and secret scanning stopping credentials before they're pushed. It means shifting these checks left so developers get feedback in the editor and the pull request, not in a quarterly pen test. And it means treating the output of every assistant as guilty until proven safe.

That's a workflow, not a single setting, and it deserves more than a paragraph. We've written a companion guide, How to Secure AI-Generated Code, that walks through the practical setup — where each control belongs in the pipeline, how to tune it so developers don't drown in noise, and how to close the provenance gap. If you're moving from "we should do something about this" to "here's our rollout," start there.

Close

AI-generated code is here to stay, and so are its security risks. The vendors and teams that come out ahead won't be the ones who resisted AI assistants — they'll be the ones who paired them with a security layer strong enough to catch what the machine gets wrong. Rainforest gives you that layer: SAST, SCA, and secret scanning working together across your pipeline, inspecting every commit no matter who — or what — wrote it. If AI is now writing a meaningful share of your codebase, that's exactly when it pays to make sure something is checking its work. See how Rainforest secures AI-generated code.

Frequently asked questions

Is AI-generated code safe?

Not inherently. AI assistants produce functional code, but functional and secure are different things, and a substantial share of AI-generated samples contain at least one security weakness. Generated code can be made safe, but only if it passes through the same automated security checks — SAST, SCA, secret scanning — you'd apply to any untrusted change. Treating it as safe by default is the mistake.

What are the biggest security risks of AI-generated code?

The main categories are insecure-by-default patterns (missing input validation, weak crypto, unencoded output), hallucinated or malicious dependencies (including slopsquatting), vulnerabilities inherited from outdated training data, hardcoded secrets, and the ownership gap created when nobody truly reviewed code a human didn't write. Most map cleanly to a detection tool you can automate in your pipeline.

Can AI write secure code?

It can, especially when you prompt it explicitly for security controls and give it context about your standards. But you can't rely on it to do so consistently, because the model optimizes for plausible, working code rather than secure code and has no awareness of vulnerabilities discovered after its training cutoff. The dependable path is to verify its output automatically rather than trust its intentions.

How do you detect vulnerabilities in AI-generated code?

With the same layered tooling that catches vulnerabilities in human-written code, run on every commit: static analysis (SAST) for insecure patterns and weak crypto, software composition analysis (SCA) for risky and non-existent dependencies, and secret scanning for exposed credentials. The key change with AI is scale — because volume and velocity are higher, these checks have to be automated and applied to every change, not sampled by manual review.

Should we stop developers from using AI coding assistants?

Banning them usually backfires — developers route around the ban and you lose visibility instead of gaining safety. The better move is to let teams use assistants and put an automated security layer in the pipeline that treats all generated code as untrusted. You keep the productivity and add a consistent backstop that doesn't depend on a human catching every flaw.

Bruno Baldo

Written by

Bruno Baldo

CMO

Um pouco de marketing e um pouco de curiosidade e temos a receita pra criar um apaixonado por cyber!

Keep reading