Safeguard
AI Security

Code injection risks in GenAI-generated code

Nearly 40% of GitHub Copilot's suggested programs contain exploitable vulnerabilities, and 19.7% of AI-generated code samples reference packages that don't exist.

Safeguard Research Team
Research
7 min read

In August 2021, researchers from NYU and the University of Calgary prompted GitHub Copilot to complete 89 coding scenarios drawn from MITRE's CWE Top 25 and collected 1,689 resulting programs. Roughly 40% of them contained a real, exploitable vulnerability — the study, "Asleep at the Keyboard?" by Pearce et al. (arXiv:2108.09293, IEEE S&P 2022), found C code fared worse than Python, but no language was clean. Five years and several model generations later, the problem hasn't disappeared, it's changed shape. A 2023 follow-up, Fu et al.'s "Security Weaknesses of Copilot-Generated Code in GitHub Projects" (arXiv:2310.02059), mined 733 real code snippets — generated by Copilot, CodeWhisperer, and Codeium — already merged into public GitHub projects and found 29.5% of the Python snippets and 24.2% of the JavaScript snippets carried a classifiable security weakness — not hypothetical benchmark code, but code developers had actually shipped. This piece walks through the concrete injection classes LLMs keep reproducing — SQL, command, and script injection — and a newer, stranger vector: models inventing package names that don't exist, which attackers can then register and poison. We'll show reproducible patterns for each and how detection actually catches them.

Why do LLMs keep suggesting injectable code?

LLMs are trained to predict the most statistically likely next token given billions of lines of public code, and a large fraction of that training corpus is itself old, insecure, or written for tutorials that favor clarity over safety. A model has seen far more StackOverflow answers using string-formatted SQL than parameterized queries, because parameterized queries are more verbose and less common in quick example code. Pearce et al. found this pattern held even when scenarios explicitly mapped to a specific CWE — the model wasn't ignorant of security, it was reproducing the statistical mode of its training distribution. Fu et al.'s data adds a second cause: models complete code in whatever context surrounds them, so a snippet dropped into an already-insecure file tends to continue that pattern rather than correct it. Neither issue is a "jailbreak" or adversarial prompt — this is default, benign-use behavior, which is why it shows up in ordinary developer workflows rather than only in red-team testing.

What does SQL injection look like in AI-suggested code?

It looks exactly like CWE-89: string concatenation or f-string interpolation building a query directly from user input. A typical Copilot-style completion for "get user by username" produces something like query = f"SELECT * FROM users WHERE username = '{username}'"; cursor.execute(query) — functionally correct for the happy path, and silently vulnerable to ' OR '1'='1 the moment username comes from a request. The fix, parameterized queries (cursor.execute("SELECT * FROM users WHERE username = %s", (username,))), is barely longer, but it's less represented in the training data for quick "how do I query a database" examples, which is exactly the kind of snippet these models are disproportionately trained on. Fu et al. classified CWE-89-adjacent injection weaknesses among the recurring categories in their 733-snippet sample, alongside command injection and improper input validation, confirming this isn't a benchmark artifact — it appears in code that made it into real repositories.

How does command and code injection show up in generated scripts?

It shows up as os.system(), subprocess.run(..., shell=True), eval(), or exec() calls built from string interpolation — CWE-78 and CWE-94. Ask an assistant for "a Python script that pings a host the user provides" and a common completion is os.system(f"ping -c 1 {host}"), which lets host = "8.8.8.8; rm -rf /" execute arbitrary shell commands. Fu et al.'s CWE breakdown specifically flagged OS command injection (CWE-78) as one of the most frequent weakness categories across the Copilot, CodeWhisperer, and Codeium snippets they analyzed. The safer pattern — subprocess.run(["ping", "-c", "1", host]), passing arguments as a list with shell=False — is a one-line change, but it requires the model (or the developer reviewing its output) to actively reject the more "natural-looking" shell-string completion, which is what tends to get suggested first.

Does this affect front-end code too?

Yes — the same pattern reproduces as CWE-79 cross-site scripting in generated JavaScript and templating code. A common AI completion for "render the user's comment" is element.innerHTML = comment rather than element.textContent = comment or an escaping helper, because innerHTML is the shorter, more frequently-seen idiom in training data for "insert this into the page." Fu et al. found JavaScript snippets carried security weaknesses at a lower but still substantial rate (24.2%) than Python, and separate research on AI-assisted development — a user study from Stanford researchers, "Do Users Write More Insecure Code with AI Assistants?" — found developers using an AI code assistant produced measurably less secure code than a control group, while simultaneously rating their own code as more secure. That combination — worse code, higher confidence — is the specific failure mode that makes AI-introduced XSS and injection bugs likelier to reach production without a second look.

What is slopsquatting and why is it a form of injection?

Slopsquatting is when an LLM invents a plausible-sounding package name that doesn't exist, and an attacker registers that exact name on a public registry with malicious code inside — turning a hallucination into a supply-chain injection point the moment someone runs pip install or npm install on the model's suggestion. A USENIX Security 2025 study by researchers at the University of Texas at San Antonio, University of Oklahoma, and Virginia Tech ("We Have a Package for You!") generated 576,000 code samples across 16 LLMs and two prompt datasets, and found 19.7% contained at least one hallucinated package reference — 205,474 unique fake names — and that 43% of those names reappeared consistently across repeated resampling of the same prompt, making them predictable enough to squat on in advance. This isn't theoretical: in early 2024, Bar Lanyado of Lasso Security registered a placeholder package matching an AI-hallucinated name, huggingface-cli (the real install path is pip install -U "huggingface_hub[cli]"), and it was downloaded more than 30,000 times in three months — including by a repository maintained by Alibaba, which had copy-pasted the hallucinated command straight from an AI suggestion.

How Safeguard Helps

None of these vectors require a new detection category so much as applying existing ones to a new authorship source: AI-generated code isn't exempt from SAST or supply-chain scanning just because a human didn't type it. Safeguard's registry-side Eagle model, now at Eagle 3.0, classifies npm, PyPI, Maven, and crates.io uploads as benign, suspicious, or malicious and runs inline on registry pre-publish hooks — the same detection surface that would catch a package registered under a hallucinated name before it reaches a build. Safeguard's built-in "Typosquat detected" guardrail independently blocks any package whose name falls within edit-distance 2 of a top-1000 package and isn't owned by the expected publisher, which covers a meaningful share of slopsquatting registrations that mimic real library names. For the injection patterns themselves — string-built SQL, shell-string subprocess calls, unescaped DOM writes — Safeguard's CI gate and Griffin AI reasoning apply the same CWE-mapped SAST rules and reachability analysis to a pull request regardless of whether a human or a model wrote the diff, and Griffin can open an auto-fix PR that swaps the interpolated string for a parameterized call. Treating AI-authored code as untrusted input to your existing pipeline, not a special case, is the most durable defense as generation volume keeps climbing.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.