A New Class of Attack: Fake Bug Reports That Hijack Coding Agents (Aug, 2026)
The AI bug-fixing pipeline nearly every team wires up first has a hole in it: an anonymous, made-up crash report can run attacker code inside the agent that holds your repo and credentials. Here's the exact vector — standard across today's automated-remediation setups — and how to close it.

About this research. This is part of our open research into the security of AI agents — the attack patterns, failure modes, and design flaws that show up as teams move agents into production. Everything we describe is built and tested on our own accounts and infrastructure; we never touch systems we don't own. When our research turns up a specific product that's exploitable, we report it to the vendor first.
A popular new setup looks like this:
- Your app crashes and sends the error to a monitoring tool.
- Some automation processes the error and turns it into a task — it might summarize it with an LLM, filter and tag it, or just drop it into a template.
- A coding agent — with access to your repo — picks up that task, fixes it, and creates a pull request.
- A human reviews the PR and merges.
Very convenient. But there's a problem: what if the crash report is fake?
It turns out an attacker needs nothing but a made-up error report to get their own code running inside the coding agent — the agent that holds access to your private source code and your GitHub credentials. The pattern is common across popular products offering this automated-fix flow, and the trust boundary is mishandled the same way across them.
This is a new attack vector against autonomous error-triage pipelines: the automated path from an incoming error report to a code change can be hijacked end to end by an attacker who never had access to anything but the public endpoint that accepts error reports.
This isn't one company's bug. It's a design pattern, and a lot of teams are building on it right now — for a very natural reason.
"AI bug-fixing" is the first automation everyone reaches for. When a team starts wiring up AI agents, this is the obvious low-hanging fruit: the errors are already collected in one place, the tasks look small and well-defined, and the payoff is easy to explain to a manager. Fix an incoming crash, open a PR, save an engineer an afternoon. Nothing about it feels risky. That's exactly why the pattern is spreading — and exactly why the attack has such a wide target.
Where the trust breaks
Attacker
↓ sends a fake error report
Monitoring tool
↓ passes it to
Triage step (summarizes, filters, or drops it into a template)
↓ passes it to
Coding agent (has your repo + credentials)
↓
Runs the "fix"
The first step accepts data from strangers. The last step has access to everything valuable. In most setups, nothing meaningful checks the data in between. That triage step might be an LLM that summarizes the error, a filter that classifies it, or — most often — just a template that drops the raw report into a ready-made instruction. None of them verify anything; they only reshape the attacker's words into something that looks official.
Here's the key point most people miss: an error report arriving at your monitoring tool does not mean the error actually happened. This is especially true when the monitoring tool collects exceptions from the frontend. And the sender controls the whole report: the error message, the file names, the line numbers, the library versions, everything. So an attacker can invent a crash that never happened, down to the last detail.
Why a fake bug is more dangerous than a real one
The trick is that a good fake bug looks easy to fix.
Imagine a report that comes with a clean error message, a file name, a line number, and an obvious fix — just update the library.
None of it has to be real. The file might not exist. The library might not be in the project. But the triage step has no way to know. And that's not an accident — it's how these pipelines are built.
The triage step doesn't verify — often it can't, and often it doesn't even try. To keep costs down and the pipeline fast, the triage step between the error and the coding agent is usually one of three things, none of which checks whether the bug is real:
- A cheaper LLM that summarizes — chosen for volume, fed only the error report, given no tools to open the repo or check the lockfile. It can't explore, so it can't catch a lie.
- A filter or classifier — routes and tags the report ("dependency error → auto-fix"), but never asks whether the underlying crash actually happened.
- A template — the simplest and most common: it pastes the raw error straight into a pre-written instruction for the coding agent. Zero intelligence, zero verification.
So whatever first touches the attacker's data is the thing least able — or least inclined — to question it. It sees a clean error and an obvious fix, and passes it on: "clear bug, easy fix, send it to the coding agent."
The core flaw: untrusted data becomes an order
This is the heart of the attack.
We just saw that the triage step doesn't verify anything. Now watch what its output turns into. Whether it summarized the report, classified it, or just wrapped it in a template, the smart, capable coding agent does the actual work. The problem is how that output gets passed along: it's handed over as a user message — the same channel a human operator would use to give instructions.
So the capable agent — the one that could have caught the lie — is never told there's a lie to catch. It doesn't receive raw, sketchy data flagged as untrusted. It receives a finished order from what looks like its operator.
AI models are trained to treat user messages as trusted commands. So when the instruction arrives, the coding agent doesn't think "here's some sketchy data from the internet." It thinks "here's my task from my boss." The fact that it all started as an anonymous, made-up report is completely lost along the way.
Fake report from a stranger → obviously untrusted
↓ (summarized, filtered, or templated)
Instruction for the coding agent → looks official
↓ (handed over as a user message)
"Your task: install X and run it" → fully trusted
And here's the surprising part: a smarter agent doesn't save you — it makes things worse. We expected a capable coding agent to notice that the file didn't exist and the library wasn't installed, and stop. It noticed all of that. Then it fixed it anyway. So it created the missing file, installed the library, and ran it to "confirm the fix."
Installing a package means running code
Once the agent installs that library, it's game over.
Installing a package runs code — through setup scripts, or just by the agent importing it and running it once to test. The agent never runs anything called "malware." It just does the most normal thing in the world:
Install the dependency and run a quick test.
That's the moment the attacker's code is running next to your source code and your credentials.
A systemic flaw, not an edge case
This isn't theoretical. The pattern — ingest an untrusted error report, analyze it, hand the result to a model that can act — is now common across popular automated-remediation tools, and the trust boundary is systematically mishandled: an anonymous, attacker-crafted error report can carry content straight into the model's instruction channel. In one case we validated end-to-end, against our own account and infrastructure, an injected error was enough to reach the integration credentials in the agent's context — sufficient to access connected code repositories. We've disclosed that finding to the vendor and are holding all specifics until it's fixed.
"A human reviews the PR" doesn't save you
The usual reassurance is that a person still reviews the pull request before merging. But the PR is the last step. By the time anyone reviews it, the agent has already downloaded your code, installed the package, run the malicious code, and read your credentials.
The attacker never needed the fix to be merged. They only needed it to run once. Reviewing the PR can stop a bad change from shipping. It can't un-steal a credential that was already taken.
How to actually stop it
Start from one assumption: the agent is already compromised. Assume a fake report gets through and the agent runs attacker code — then design so that when it does, nothing valuable is in reach. Most of the anti-patterns above disappear once you stop trusting the agent and start containing it.
- Don't pass the triage step's output as a trusted order. Summarized, filtered, or templated, it's still untrusted data from the internet. Label it that way — don't hand it to the coding agent as if a human wrote it.
- Verify the problem is real. Before any fix, confirm the bug actually exists in the codebase and the agent can reproduce it. Does the file exist? Is the library actually in the project? Does the crash happen? If not, treat the report as unverified — don't start creating files and installing packages.
- Don't let the agent install new, untrusted packages. Installing a package runs its code. Lock the dependency set: the pipeline should only resolve packages already vetted and pinned in your lockfile, and reject any fix that tries to add or run something new — enforced automatically, not left to the agent's discretion.
- Don't hand an AI agent your GitHub account. Follow least privilege. Scope it to the one repo it's working on with short-lived, narrow tokens — not a credential that can read and push everywhere. It's the difference between one throwaway branch and your entire org.
Newsletter
Get new agent engineering posts in your inbox
Occasional practical notes on secure agent runtimes, orchestration, and AI engineering.