AI-Generated Code Ships. Your Security Review Doesn't Know It's AI.
The developer opened their IDE, described the endpoint they needed in a comment, and the coding assistant wrote it. The code worked. It passed unit tests. It got through code review. It deployed to production.
It also had a SQL injection vulnerability in the user lookup, an MD5 hash on what was supposed to be a password, and a dependency on a package that does not exist - at least, it did not exist until someone registered it the week after the code shipped.
This is not an edge case. It is what AI-assisted development looks like at scale, and most security review processes were not designed for it.
What the Models Get Wrong, Consistently
LLMs are good at generating syntactically valid, functionally plausible code. They are considerably less reliable on security properties, for a structural reason: they were trained on the entire corpus of publicly available code, which includes an enormous amount of insecure code. They have learned the patterns that appear most frequently, not the patterns that are most correct from a security standpoint.
The specific failure modes show up with enough regularity that researchers have catalogued them. String concatenation into SQL queries instead of parameterized statements. MD5 and SHA-1 for anything security-sensitive. Input validation that looks complete but misses edge cases. Error handling that leaks stack traces or internal information. Cryptographic implementations that follow the shape of correct code without the substance of it.
The particularly treacherous category is crypto. LLMs produce code that resembles secure implementations - it calls recognizable functions, it has the right structure - but gets the details wrong in ways that are not visible in code review unless the reviewer knows specifically what to look for. Using a static IV. Using ECB mode when you wanted CBC. Generating a random key that feeds into a hash function when what you needed was a CSPRNG. The code looks like it does the right thing and does not.
The Package That Did Not Exist
A less intuitive problem is what researchers have started calling slopsquatting: LLMs generating import statements for packages that do not exist.
When an LLM generates code that imports a library, it is producing a plausible-sounding name based on patterns in its training data. Most of the time this hits a real package. Sometimes it generates a name with no corresponding real package - a plausible-but-fictional dependency. The developer runs the code, sees an import error, and moves on. But before they do, the package name has appeared in their codebase, in commit history, and potentially in documentation.
Attackers have identified this pattern and are watching for it. A hallucinated package name that appears repeatedly in AI-generated code examples is a registration opportunity. The attacker registers the package in the relevant registry, publishes a malicious version, and waits for developers who took the AI's suggestion to run their package manager. The developer installs a package that looks legitimate, has a plausible description, and happens to contain a backdoor.
This is a supply chain attack with an unusually passive entry point. The LLM created the attack surface. The developer who trusted the output opened the door.
The Review Problem
Code review processes were designed around the assumption that the reviewer needs to understand whether the author intended what the code does and whether the logic is correct. Security review was bolted on to that foundation: look for the bad patterns, check the obvious vulnerability categories, flag what looks wrong.
AI-generated code creates a different problem. The author did not write the security-sensitive section - the model did - and neither the author nor the reviewer may recognize that. When a developer tells a colleague they used an AI assistant for a section, the reviewer sometimes actually looks more carefully, treating AI output with appropriate skepticism. More often, the code shows up in a PR indistinguishable from any other, reviewed on the same criteria, and merged.
The psychological dynamic cuts against good outcomes here. AI-generated code often looks authoritative. It is well-formatted, it follows the conventions of the codebase, it has reasonable variable names. The visual signals that usually prompt skepticism - unfamiliar patterns, rushed code, unusual structure - are often absent. The vulnerabilities are baked in invisibly.
What Actually Helps
SAST tools catch some of this. A scanner that flags SQL injection patterns or weak cryptographic usage will catch the most common failures whether the code was human-written or model-generated. The coverage is not complete - models produce patterns that scanners miss, and scanners flag false positives in AI-generated code at roughly the same rate as everything else - but the automated layer is worth more than it was before your developers had access to a coding assistant, because the volume of code entering review has increased and manual review is not scaling with it.
Dependency auditing needs to account for hallucinated packages. When a developer installs a new dependency based on an AI suggestion, checking the package's publication date, download history, and author history is a reasonable step. A package with 47 downloads, published two weeks ago, with no prior commit history and a description that matches exactly what an LLM would generate for that use case deserves more scrutiny than a well-established library with a long track record.
On the process side, making AI assistance visible in code review is not paranoia. Developers know when they used a model for a nontrivial section. A note in the PR description - "generated, reviewed, modified" - gives reviewers the information they need to apply appropriate scrutiny. Treating AI assistance like any other code generation tool means applying the same security review discipline you would to any code you did not fully reason through yourself.
The models are useful. They are not competent security reviewers. Treating AI-generated code like a first draft from a fast but junior developer - inspect for logic, inspect for security, test, modify, understand before shipping - is the mental model that keeps AI-assisted development from becoming AI-assisted vulnerability introduction.