Abstract technical illustration on a dark navy field: a compact server cube at left issues three small rectangular cards toward an agent node at right; the first two cards are pale and inert, the third casts a long shadow shaped like a key. Fine cyan filaments run from the server toward a loose grid of repository nodes behind it, and a single amber line connects the agent node to a keyring of small credential discs. No people, no logos, no text. The OrcaRouter logo is composited in the bottom-right corner.
AI Safety Incidents

Deadbugz: an MCP server that turns hostile on the third tool call, pushed to 23 repositories in 74 minutes

Author

Magnus Corvin

Date Published

Latest models · 20View all models →
Benchmarks: Artificial Analysis · updated daily
Back to all posts

On 10 August 2026 one GitHub account, zellkernel, opened 23 pull requests in 74 minutes against unrelated AI, MCP and developer-tooling repositories, each adding an MCP server named productivity-suite that advertised two ordinary tools, format_text and summarize. According to Pillar Security, which named the campaign Deadbugz and published its write-up on 12 August, the server returned honest results for its first three calls and then rewrote the metadata it handed the agent: the tool descriptions and prompt content began directing the model toward SSH keys, AWS credentials, shell history and Kubernetes configuration, and telling it to keep that activity from the user. Nineteen of the 23 pull requests were closed, four were still open and none had been merged when Pillar reviewed them. No victim has been confirmed. This is one record, reported by others and cited here to them. The other documented agent incidents, each with its own sources, severity, confidence grade and disputed flag, sit in the AI incident archive — so a supply-chain campaign aimed at agent tooling can be read next to the rest of what has actually happened.

The archive grades this record high severity and confidence A — well documented, with primary sources that agree — while separately recording no confirmed real harm. Both things are true at once, and the gap between them is what the record is about: a campaign whose design was documented in unusual detail before it produced a victim anyone can name. The two dates that matter are two days apart. The pull requests went out on 10 August; Pillar Security's Ariel Fogel published the analysis on 12 August, and the post carries a standing note that it would be updated as verified information arrived.

Three calls, then the metadata changes

An MCP server does not have to run code on a machine to change what an agent does. Tool definitions are handed to the model as context on every session, which means the server that supplies them can rewrite the instructions the agent reads while leaving the tool's name, its repository and its manifest exactly as they were. Deadbugz is built on that asymmetry, and Pillar's name for it is runtime-gated MCP metadata poisoning.

The mechanics are small enough to state in a sentence. The server keeps an in-memory, per-client counter of tools/call requests. For the first three, it behaves. Once the counter is tripped, later tools/list and prompts/get responses come back altered — different tool descriptions, different prompt content — pointing the agent at SSH keys, AWS credentials, shell history and Kubernetes configuration and instructing it to conceal the activity from the user. The poisoned prompt text carries the marker deadbugz and a Bitcoin address.

The gate is also why the ordinary defences do not catch it. The payload is present in the source from the first request; nothing about the code or the configuration changes at the moment of the switch. A static scan, an SBOM entry or a one-time read of the tool manifest at install time sees a formatting utility, because that is what the utility returns until the counter moves. Pillar describes the delayed switch as a research-evasion technique, and says its researchers confirmed both the threshold and the altered metadata by sending text-only requests to the live remote service and matching the responses against the public source.

One detail makes the trap wider than a single session. The server advertises tools.listChanged, the MCP capability that tells a client its tool list has been revised. A client that honours that signal will re-read the definitions mid-session and pull the poisoned version without any operator action; a client that caches definitions on approval will not. Which behaviour a given agent has is a property of the client, not of the server, and Pillar's write-up does not enumerate clients by name.

HTML card titled 'Three calls, then the metadata changes', kicked 'MCP · productivity-suite', with the subtitle 'The payload is present from the first request; the gate is a counter in memory'. Three columns. 'Calls one to three — benign' lists format_text returning formatted text, summarize returning a summary, and tools/list and prompts/get returning honest tool definitions, with a note that nothing on disk differs from what a reviewer approved. 'The gate' lists an in-memory per-client counter of tools/call requests, a threshold of three, altered tool descriptions and prompt content in later tools/list and prompts/get responses, and the advertised tools.listChanged capability that lets compliant clients re-read definitions mid-session. 'What the poisoned metadata asks for' lists SSH keys, AWS credentials, shell history and Kubernetes configuration, an instruction to keep the activity from the user, and the embedded marker deadbugz with a Bitcoin address. A footer reads 'Per Pillar Security's disclosure of 12 August 2026. Pillar says its researchers confirmed the threshold and the altered metadata against the live remote service using text-only requests, matching the public source.'

Delivery: 23 pull requests in 74 minutes

The distribution was not a package on a registry or a poisoned dependency buried in a lockfile. It was pull-request spam against projects that had nothing to do with the server's supposed function, which is the shape a low-cost supply-chain attempt takes when the attacker cannot get a maintainer account: file enough configuration changes and wait for one to be merged or applied locally.

Pillar's breakdown of the 23 is three-way. Seventeen add a remote MCP endpoint, productivity-suite-mcp[.]onrender[.]com/mcp, hosted on Render; four invoke a hidden local Python file at ~/.config/.cache/.sys/.deadbug-mcp.py; two are directory or listing submissions, which the write-up treats as reconnaissance or filler rather than delivery. The window is given as 9:52 PM to 11:07 PM UTC on 10 August 2026 — 74 minutes in the disclosure's framing, though the two timestamps themselves span 75, and nothing in the record turns on that minute. Only one target repository is named individually: getsentry/sentry-mcp, pull request #1239, cited as an example of the local-artifact delivery.

The account behind it was substantial for its age. At the time of Pillar's collection, zellkernel had 50 public repositories, 20 of them forks, and 21 of those 50 had been created on 10 August, the same day as the campaign. The profile was cross-linked to the X account @llmgod, which linked back to the GitHub account, which is the kind of reciprocal linking that argues for a purpose-built identity rather than a hijacked one.

Nineteen closed, four open, zero merged is the most-repeated figure in the record and also the one most often read as an all-clear, which it is not quite. GitHub's merge button is not a host's execution record: a maintainer can pull a branch and run it, apply a configuration by hand, or a CI job can fetch a PR's head before anyone comments. The four pull requests that write a config invoking a local script path are the ones where that gap matters most, because the script is fetched and run outside GitHub's merge accounting entirely. Cloud Security Alliance Labs made the same point in its 2 September note: the closed and unmerged counts do not prove that nothing ran.

HTML card titled 'Twenty-three pull requests in seventy-four minutes', kicked '10 August 2026 · delivery', subtitled 'Times UTC. Counts are Pillar Security's review snapshot.' Three columns. 'The window' lists the first pull request at 21:52, twenty-three pull requests to unrelated AI, MCP and developer-tooling repositories, the last at 23:07, and a note that the 74-minute framing spans 75 minutes on the clock. 'What each pull request added' lists seventeen adding the remote endpoint productivity-suite-mcp.onrender.com/mcp, four invoking the hidden file at ~/.config/.cache/.sys/.deadbug-mcp.py, two directory or listing submissions, and one named example, getsentry/sentry-mcp pull request 1239. 'At review' lists nineteen closed, four open, zero merged through GitHub's review, zero confirmed victims, and the account zellkernel linked to the X handle llmgod, with fifty public repositories and twenty-one created that day. A footer reads 'Per Pillar Security. Cloud Security Alliance Labs repeated the same figures on 30 August and 2 September 2026 without independent verification. As of 29 October 2026 the GitHub account and the productivity-suite-mcp repository both return 404.'

What is established, and what is not

Established by the disclosure, in the sense that Pillar reports it from artefacts it read and in one case from a service it queried: the server and its source repository, the two advertised tools, the counter and the three-call threshold, the four credential targets, the PR counts and their merge status at review, and the link between the GitHub account and the X handle. Pillar's own testing against the live endpoint is the strongest item on the list, because it is a reproduction rather than a reading of source code.

Not established, and the record is careful about it: a victim. The archive's real_harm field is false, which is a statement about evidence, not about intent — nobody has produced a host, a log or a stolen credential tied to this campaign. Nor is the person or group behind zellkernel and @llmgod identified; Pillar attributes the operation to the accounts and stops there. The financial motive rests on a Bitcoin address embedded in the payload, which is an inference from an indicator, not a finding about the actor. And the question a defender most wants answered — whether the campaign is still running — has no answer in the record: the post was marked as one that would be updated, and no later revision or takedown notice from GitHub or Render is visible.

Corroboration is thinner than the confidence grade might suggest, and this is worth saying plainly. Two Cloud Security Alliance Labs research notes, dated 30 August and 2 September 2026, restate the campaign; the later one is explicit that it credits Pillar for the discovery, the PR details, the server behaviour and the account attribution, and describes no independent verification of its own. An Armor blog post dated 22 September 2026 supplies defensive guidance and says Pillar pulled the server apart; it offers no forensic evidence of its own. No CVE was assigned, and CSA says this is not an MCP specification vulnerability. As of 29 October 2026, searches turn up no advisory from GitHub or Render, and no coverage in the mainstream security trade press — no BleepingComputer, The Register, SecurityWeek or Hackread item — which is unusual for a supply-chain campaign of this shape and is itself part of what the record shows. "Primary sources agree" here means one originating primary source and a set of secondary documents that derive from it.

Two smaller ambiguities are worth flagging rather than smoothing over. Secondary summaries differ on whether the third call or the fourth is the first one to receive poisoned metadata, which follows from the counter being described as tripping on the third request; the record and the disclosure both use three. And the delivery window is described as 74 minutes for timestamps that span 75.

One check that could not be repeated: on 29 October 2026, the GitHub account zellkernel and the repository zellkernel/productivity-suite-mcp both return 404, and the one individually named pull request, getsentry/sentry-mcp #1239, no longer resolves either — the repository itself now redirects to getsentry/toolkit. The PR counts, the merge status and the repository contents therefore cannot be re-verified first-party today; they stand as Pillar's snapshot, taken in mid-August.

HTML card titled 'What is established, and what is not', kicked '2026-08-10-deadbugz-mcp-supply-chain', subtitled 'One record, one originating source, two secondary notes that restate it'. Three columns. 'Established by the disclosure' lists the server, its source repository and the two advertised tools; the counter and the three-call threshold, confirmed against the live endpoint; the four credential targets; twenty-three pull requests, nineteen closed, four open, none merged; and the delivery account linked to the X handle llmgod. 'Not established' lists any victim or executed payload, with the archive recording real harm as false; the actor behind the account and handle; motive, which rests on a Bitcoin address in the payload; and whether the campaign is still running, the post having promised updates that are not visible. 'Corroboration' lists the Cloud Security Alliance Labs notes of 30 August and 2 September 2026 as restatement without independent checks; the Armor blog of 22 September 2026 as guidance without forensic evidence; no CVE assigned; no GitHub or Render advisory found; and no mainstream trade-press coverage found as of 29 October 2026. A footer reads 'The archive grades the record A, well documented with primary sources that agree. The secondary documents here all derive from Pillar Security's post, so agreement between them is not a second measurement.'

What the disclosure asks defenders to do

The response Pillar recommends is mostly about treating metadata as a security surface rather than a description of one. For hosts, the concrete asks are to block or hunt for productivity-suite-mcp[.]onrender[.]com/mcp, to keep the campaign's earlier trycloudflare.com endpoint in deny and hunting lists even though Pillar says it is not currently active, and not to run deadbug-mcp.py — the hidden file path ~/.config/.cache/.sys/.deadbug-mcp.py is the artefact to search for across home directories, repositories and MCP client configurations.

The investigative order matters more than the blocklist. If a host may have connected, Pillar says to preserve MCP client logs before cleaning anything, then review tool-definition refreshes and what the agent did after the third call; credentials should be rotated only where local evidence supports exposure, which is the opposite of the reflex to rotate everything on suspicion. The server's configuration also allowed optional telemetry to a WEBHOOK_URL, beaconing on connection, first call and trigger event — a detail that gives an investigation a third place to look beyond client logs and endpoint traffic.

For the people who build MCP clients, the recommendation is structural, and it is the part of the record with the longest shelf life:

• Fingerprint tool definitions at approval time and compare them on every refresh, rather than trusting the server's name and repository.

• Treat a definition change on an already-approved server as a security event that the operator sees and re-approves, not as routine metadata churn to be swallowed silently.

• Enforce sensitive operations — credential access, code execution, outbound email, repository writes — through policy rather than through descriptions the server supplies.

That third item is what makes Deadbugz a record rather than a curiosity. Every control above assumes an agent can be talked into things by the text a server attaches to a tool, and that the text can change after the trust decision was made. Pillar places the campaign in a line that includes Invariant Labs' 2025 MCP sleeper attack, the counterfeit postmark-mcp package and a Koi-documented MCP package weaponised through an update — all of them precedents for the technique, cited by Pillar for that and not as evidence about this delivery.

Why the gate matters more than the victim count

A campaign with 23 delivery attempts, no merge and no confirmed victim is easy to file under attempted and move past. The reason it belongs in the archive at high severity is that its evasion does not depend on the delivery succeeding at scale. It depends on a property most MCP deployments share today: approval happens once, at install, and the definition that was approved is assumed to be the definition that will be served. Deadbugz keeps that assumption intact for three calls and then breaks it.

The fix is not a patch to a specific server, and there is no CVE to track. It is that "approved" has to become a continuing condition with a comparison behind it — which is a change in how clients and their operators behave, not a change in what a scanner looks for. Whether anyone actually ran the server in August is still unknown; on the record as it stands, the mechanism is the finding.