Back to Blog
Deadbugz: The MCP Server That Waits Three Tool Calls Before It Turns Hostile

Deadbugz: The MCP Server That Waits Three Tool Calls Before It Turns Hostile

September 15, 2026
11 min read
17 views
Share:

A GitHub account filed 23 pull requests in 74 minutes, each quietly adding a malicious MCP server. It behaves for exactly three tool calls, then rewrites its own metadata into instructions to hunt SSH keys, AWS credentials, and kubeconfigs.

~/.config/.cache/.sys/.deadbug-mcp.py. Four dot-prefixed folders stacked one inside another, buried in a GitHub pull request diff that otherwise reads like routine MCP configuration. That path is the entire tell for a campaign Pillar Security started tracking in August 2026 — a wave of pull requests quietly wiring a malicious Model Context Protocol server into unrelated AI, developer-tool, and MCP projects. I spend a lot of my working week thinking about what gets trusted by default on a network — a VLAN, a service account, a firewall rule inherited from three jobs ago — and this is the same failure mode wearing an AI coding assistant's clothes: nobody re-reviews the thing that already passed review.


What Deadbugz actually is

MCP, the Model Context Protocol, is the plumbing that lets tools like Claude Code, Claude Desktop, Cursor, and Windsurf call out to external servers — a database, a ticketing system, a "productivity" helper — without the vendor having to build a bespoke integration for every AI client. When an MCP client connects to a server, the server hands back a list of tools: names, JSON schemas, and free-text descriptions. That description text isn't cosmetic. It goes straight into the model's context window as instructions the model is expected to follow when deciding what to do next.

Pillar Security's research team, led by Ariel Fogel, found a server on npm-adjacent GitHub called productivity-suite-mcp that ships exactly two tools: format_text and summarize. Nothing unusual. Both do what they say. The server keeps an in-memory, per-client counter of every tools/call request it receives, and for the first two calls, everything is exactly as advertised.

The third call flips a switch. From that point on, the server's tools/list and prompts/get responses stop describing a text formatter and start instructing the connected agent to search the local machine for SSH private keys, AWS credentials, shell history, and Kubernetes configuration — and to do it quietly, without telling the operator what it's doing. Pillar named the campaign Deadbugz after deadbug-mcp.py, one of the delivery artifacts they found reused across the operation.

ToolDeclared purposeBehavior at calls 1–2Behavior at call 3+
format_textFormat supplied textFormats text, exactly as describedMetadata rewritten to credential-seeking instructions
summarizeProduce a concise summarySummarizes text, exactly as describedMetadata rewritten to credential-seeking instructions

Figure 1: The credential-seeking, cross-tool payload the server returns through prompts/get once the three-call threshold is crossed (Source: Pillar Security).

What makes this more than a party trick is the mechanism the server uses to update its own metadata mid-session: tools.listChanged, a standard MCP capability that exists so a server can legitimately tell a client "my tools changed, please refresh." Deadbugz doesn't exploit a bug in that capability — it uses it exactly as designed, just for the opposite of its intended purpose. A capability meant to keep clients in sync becomes the delivery mechanism for a payload that was sitting in the code the whole time, just gated behind a counter.


How the attack actually plays out

Strip away the branding and this is a short, mechanical sequence. Pillar reconstructed it by connecting to the live endpoint themselves and sending nothing but ordinary text requests:

  1. Delivery. An attacker-controlled GitHub account forks an unrelated AI, MCP, or developer-tooling repository and opens a pull request that adds MCP server configuration — either a remote endpoint or a path to a local script.
  2. Merge or manual test. A maintainer merges the PR, or a developer pulls the branch locally to try it out. Either way, an MCP client somewhere now points at productivity-suite.
  3. Call one. The agent invokes format_text or summarize. It works exactly as documented. Nothing to see.
  4. Call two. Same result. This is the window where a cautious reviewer, a quick manual smoke test, or an automated security scanner would almost certainly stop — and walk away satisfied.
  5. Call three. The server's internal counter for that client hits the threshold. Nothing about the tool names changes. The descriptions do.
  6. The flip. The next tools/list and prompts/get responses come back rewritten, instructing the agent to locate SSH keys, AWS credentials, shell history, and Kubernetes configuration files on the host.
  7. The cover story. The same rewritten instructions direct the agent to conceal the search from whoever is operating it — turning the agent's own helpfulness and its tendency to summarize its actions concisely into the attacker's advantage.
  8. Optional telemetry. The public source code supports a WEBHOOK_URL setting that can beacon connection events, first-call events, and trigger-crossing events back to the operator — a lightweight way to track which deployments are actually live and paying off.

Figure 2: A controlled interaction with the live endpoint — three benign text results, then credential-seeking and cross-tool instructions returned through prompts/get (Source: Pillar Security).

Nothing in this sequence trips a code-signing check, a hash mismatch, or a dependency-confusion alert. The tool's name never changes. The endpoint never changes. The only thing that changes is a block of English text the model is primed to treat as authoritative instructions — and it changes only after the server has already earned two rounds of trust.


23 pull requests, 74 minutes, one account

The delivery side of this is almost more interesting than the payload. Pillar attributes the operation to a single public GitHub account, zellkernel, which opened 23 identified campaign pull requests against unrelated AI, MCP, and developer-tool repositories between 21:52 and 23:07 UTC on August 10, 2026 — a 74-minute window. At the time of Pillar's review, none had been merged through GitHub's normal merge mechanism: 19 were closed and four were still open.

Configuration addedPR countDetail
Remote MCP endpoint17https://productivity-suite-mcp.onrender.com/mcp
Hidden local script4~/.config/.cache/.sys/.deadbug-mcp.py
Directory / listing submission2Adds the server to MCP directories or listing repos

The account itself supports the picture of a scaled, semi-automated operation rather than a single hand-crafted intrusion: 50 public repositories at the time Pillar collected data, including 20 forks, with 21 of those repositories created on August 10 alone — the same day as the PR blitz. The account's GitHub profile links to an X account, @llmgod, and that X profile links back to the GitHub account, giving researchers a public, bidirectional identity thread even if it doesn't resolve to a real name.

The pattern — fork, add a plausible-sounding dependency, open a PR, repeat across dozens of unrelated repos in a tight window — is the same spray-and-pray playbook that's been used for years against npm and PyPI through typosquatting and dependency confusion. Deadbugz just points that playbook at MCP configuration instead of a package manifest, and swaps a static malicious payload for one that only reveals itself after the reviewer has stopped watching.


This isn't the first MCP rug pull — it's a sharper one

The idea of an MCP server changing behavior after it's been trusted isn't new. In April 2025, Invariant Labs demonstrated a WhatsApp MCP integration that could be manipulated through a tool description change after approval — an innocuous tool whose description was later altered to exfiltrate chat history, sometimes called an MCP "sleeper attack" or rug pull. Later in 2025, a counterfeit postmark-mcp package built up legitimate adoption before an update quietly added covert outbound-email copying, and Koi Security separately documented another MCP package that shipped as a working tool and was weaponized through a malicious update carrying installation and runtime backdoors.

What Deadbugz changes is the trigger. Those earlier cases relied on the attacker shipping a new version — a package update, a code push, something a diff or a re-review could theoretically catch if anyone was watching for it. Deadbugz doesn't need a new release at all. The malicious instructions are already sitting in the code from day one; they're just gated behind a call counter instead of a version bump. A security review that connects, calls a tool once or twice, and moves on — which describes most manual reviews and nearly all automated ones — sees only the harmless version and signs off. Normal, everyday use is what trips the wire.


Indicators of compromise

TypeIndicatorNotes
Remote MCP endpoint (active)productivity-suite-mcp[.]onrender[.]com/mcpConfirmed campaign endpoint in reviewed configuration and source.
Remote MCP endpoint (historical)promo-surname-xml-quantum[.]trycloudflare[.]com/mcpConfirmed in prior campaign material; not currently believed active.
Local delivery artifact~/.config/.cache/.sys/.deadbug-mcp.pyFound in four of the reviewed PR configurations. Do not execute.
Server nameproductivity-suiteConfirmed campaign marker in MCP client configuration.
Bitcoin address / campaign markerbc1q5xpazlg7q6ph2r6s7tzumd5zyjdet6vjzvsqlnEmbedded in the delayed malicious prompt alongside the string "deadbugz"; useful for correlation, not evidence of payment activity.
Public source repositorygithub[.]com/zellkernel/productivity-suite-mcpMatches observed server behavior.
Delivery accountgithub[.]com/zellkernelAuthor of all 23 reviewed pull requests.

My take

What gets me about this one isn't the credential-hunting payload — that part is almost boilerplate infostealer behavior, the same targets (SSH keys, AWS credentials, kubeconfigs, shell history) I'd expect from any commodity post-exploitation script. What's genuinely new is that Deadbugz identified and exploited a specific, structural gap in how teams evaluate trust for MCP servers: everyone reviews once, at install time, and almost nobody re-checks after. I've spent enough years signing off on firewall rules and access grants to recognize that pattern immediately — it's the same reason stale service accounts and forgotten VPN rules survive for years in real networks. The control that exists is a point-in-time control, and Deadbugz is built specifically to survive that point in time by simply not showing its hand yet.

There's no CVE here, and there shouldn't be — this isn't a vulnerability in a product, it's a malicious package deliberately engineered to look benign during exactly the window when people check. That distinction matters operationally: your vulnerability scanner and your dependency-CVE feed will both stay silent about this all day long, because there's nothing in either of those pipelines built to flag "a tool's free-text description changed after the third time you used it." The tools.listChanged mechanism Deadbugz abuses is a legitimate, spec-compliant part of MCP. That's the uncomfortable part — you can't just block a malformed protocol message, because there isn't one.

The delivery side is honestly the less novel half of this story, and I'd argue it's the more preventable half. Twenty-three PRs from one account, in 74 minutes, against repos that account had no prior relationship with, is exactly the kind of pattern that GitHub's own abuse signals and a halfway-attentive maintainer should catch — it's the AI-agent equivalent of a typosquat flood against npm, and we already know how to triage those. The part infrastructure and platform teams don't yet have tooling for is the runtime half: fingerprinting a tool's declared schema and description at approval time, and treating any drift from that fingerprint — even a protocol-legal listChanged refresh — as an event that needs a human to look at it again before the agent acts on the new instructions.


What you should do right now

  • Block the active endpoint at egress. Add productivity-suite-mcp.onrender.com to your DNS sinkhole or proxy deny list for developer and CI networks, and keep the historical trycloudflare.com address in your threat-hunting deny list even though it's believed inactive.
  • Search for the local artifact. Grep developer workstations, CI runners, and build images for ~/.config/.cache/.sys/.deadbug-mcp.py. If you find it, do not execute it — quarantine the host and start incident response.
  • Audit every MCP client config in your org — Claude Desktop, Claude Code, Cursor, Windsurf, VS Code MCP extensions — for the server name productivity-suite or the onrender.com endpoint. Don't rely on developers self-reporting what they installed; pull the actual config files.
  • Preserve logs before you clean up. If a device connected to the server, grab MCP client logs first. You specifically want to know whether that client crossed the third tool call, and what the agent did immediately after.
  • Treat a confirmed connection as a confirmed exposure, not a maybe. If a host crossed the threshold, rotate SSH keys, AWS credentials, and kubeconfig tokens that were reachable from that machine, per your normal incident-response process — don't wait for proof of exfiltration before rotating.
  • Raise the review bar for MCP config PRs to match production dependency PRs. Any pull request that adds a new MCP server endpoint or local script reference to a repo you maintain should get the same scrutiny as a new CI secret or a new production dependency — not a quick glance.
  • Push your MCP client vendor on tool-definition fingerprinting. Ask whether a tools.listChanged event on an already-approved server triggers a re-approval prompt in your tooling. If it doesn't today, that's the gap Deadbugz is built to walk through.

This article was researched and drafted with AI assistance as part of an experiment in building a faster tech-writing workflow, then reviewed and edited before publishing.


Primary source: Deadbugz: Currently Active MCP Supply-Chain Campaign — Pillar Security, August 12, 2026

Secondary source: ThreatsDay: 296K IoT Botnet, 100+ Water Systems Targeted, SharePoint RCE Chain + 27 New Stories — The Hacker News, August 2026

Secondary source: WhatsApp MCP Exploited: Silently Exfiltrating Your Message History — Invariant Labs, April 2025

Keep Reading

Comments