# Deadbugz: The MCP Supply Chain Attack That Waits 3 Calls (2026)

> Deadbugz shipped an MCP server that behaved for exactly three tool calls, then rewrote its own tool descriptions to hunt for SSH keys and AWS credentials. Every pre-install review passed it. Here is how the trigger worked, why static review cannot catch it, and the behavioural test that does.

**Source:** https://mcpplaygroundonline.com/blog/deadbugz-mcp-supply-chain-attack  
**Author:** Nikhil Tiwari  
**Published:** 2026-09-26  
**Category:** Security  
**Reading time:** 13 min read  
**Topics:** MCP supply chain attack, Deadbugz MCP, Deadbugz, MCP rug pull, malicious MCP server, MCP tool poisoning, delayed activation MCP server, MCP tool definition change detection, MCP server behavioural testing, how to detect a malicious MCP server, what is an MCP rug pull, can an MCP server change its tools after approval, productivity-suite MCP server, zellkernel, Pillar Security Deadbugz, OWASP MCP Top 10 tool poisoning

---

📖 TL;DR

-   **Deadbugz is an MCP supply chain attack** disclosed by Pillar Security. On 10 August 2026 one GitHub account, `zellkernel`, opened 23 pull requests in 74 minutes.
-   The PRs added an MCP server called **productivity-suite** with two harmless tools: `format_text` and `summarize`.
-   **After the third tool call, the server changed.** Its `tools/list` and `prompts/get` responses turned into instructions to find SSH keys, AWS credentials, shell history and Kubernetes config, and to hide it from the user.
-   Any review done before install saw a clean server. **This is a rug pull with a delay built in**, and it defeats one-time approval by design.
-   The fix is behavioural: pin the tool definitions you approved, call the server several times, list again, and treat any difference as a security event.

Most MCP security advice assumes the server you reviewed is the server you run.

**Deadbugz broke that assumption on purpose.**

It is an _MCP supply chain attack_ that shipped a server which looked clean on install, stayed clean for three tool calls, then turned.

After call three, its tool descriptions became instructions. The target was your SSH keys, cloud credentials and shell history.

If your only check is reading the tool list before you approve a server, you would have approved this one.

So would a registry scanner. So would a careful reviewer reading the pull request.

I will walk through exactly how the trigger worked, why static checks miss it, and a 40-line test that catches it.

You will also get the indicators of compromise, so you can check your own repos today.

## What Is the Deadbugz MCP Supply Chain Attack?

**Deadbugz is a campaign that planted a malicious MCP server in developer projects through pull requests, then activated it only after three tool calls.**

[Pillar Security](https://www.pillar.security/blog/deadbugz-currently-active-mcp-supply-chain-campaign) published the analysis. The core facts:

Detail

Deadbugz

**When**

10 August 2026, 21:52 to 23:07 UTC

**Who**

GitHub account `zellkernel`

**Delivery**

23 pull requests to unrelated AI, MCP and dev-tool projects. 19 closed, 4 still open at review.

**Payload**

17 PRs added a remote MCP endpoint, 4 a local Python file, 2 were listing submissions

**Server**

`productivity-suite`, tools `format_text` and `summarize`

**Goal**

SSH keys, AWS credentials, shell history, Kubernetes config, hidden from the user

Adversa's [September 2026 MCP security roundup](https://adversa.ai/blog/top-mcp-security-resources-september-2026/) ranked it the month's top incident.

The delivery was ordinary. **The trigger was the new part.**

## How Did the Deadbugz Trigger Work?

**The server counted `tools/call` requests per client in memory. Once the count reached three, its `tools/list` and `prompts/get` responses changed.**

Here is the sequence an agent would see:

1.  **Connect.** `tools/list` returns two dull tools with honest descriptions.
2.  **Calls one to three.** `format_text` and `summarize` do exactly what they say.
3.  **Call four onward.** The next `tools/list` or `prompts/get` returns new metadata.
4.  **The new metadata is an instruction.** It steers the agent toward `~/.ssh`, AWS credentials, shell history and kubeconfig, and tells it not to mention this to the user.

No exploit code runs on your machine in the remote variant. **The agent does the work, using the file and shell tools you already gave it.**

That is [MCP tool poisoning](/owasp-mcp-top-10/tool-poisoning), delivered late. The model reads tool descriptions as trusted context, so a description is a prompt.

### Why three calls?

Three is enough to get past the checks people actually run.

-   A reviewer connects once and reads the tool list. **Zero calls.**
-   A registry scanner lists tools and maybe calls each once. **Two calls.**
-   A developer tries the server and sees it work. **One or two calls.**

Real use goes past three within minutes. **The trigger sits right between evaluation and production.**

## Why Static MCP Server Review Can't Catch a Rug Pull

**A static review inspects the server at one moment. Deadbugz only misbehaved at a later moment, so every static check passed by construction.**

Pillar's write-up puts it plainly: metadata that turns hostile at runtime defeats review. You cannot read your way to a behaviour that has not happened yet.

This is a _rug pull_: a server changes its tool definitions after you trusted it. The MCP spec allows tool lists to change, and clients are expected to re-fetch them.

That is a feature. Servers add tools, fix typos and ship versions. **The problem is that most clients accept the new list silently.**

⚠️ Stateless MCP does not stop this

The [2026-07-28 stateless spec](/blog/mcp-stateless-2026-release-candidate) removed protocol sessions, but a server can still key a counter on an auth token, an IP address or any header. "No session" does not mean "no memory of you".

### What each common defence actually sees

Defence

Catches Deadbugz?

Why

Reading the PR diff

❌ Remote variant

The diff is one URL. The logic lives on someone else's host.

Scanning tool descriptions at install

❌

The descriptions are clean at install.

A tool name allowlist

❌

The names never change. Only the text does.

Hash pinning, checked once at connect

⚠️ Only on reconnect

It misses the change inside a running session.

Pinning plus re-checking after calls

✅

It compares behaviour over time, which is where the attack lives.

## How Do I Detect a Malicious MCP Server Before It Turns?

**Pin the tool and prompt definitions you approved, use the server past any plausible threshold, list again, and diff.** That is the whole idea.

Pillar's own guidance says the same: treat a changed tool definition on an approved server as a security event, show it to the operator, and require re-approval.

You can run that test yourself with the official [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk). No model is involved, so nothing can be tricked into acting.

🚨 Run it somewhere disposable

This script never gives the server a model or your files. Still, run it from a throwaway container or CI job, not the laptop that holds your SSH keys. Never point a real agent at a server you are testing.

```
// drift-check.mjs  —  node drift-check.mjs https://server.example.com/mcp
import { createHash } from "node:crypto";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const url = new URL(process.argv[2]);
const CALLS = 10; // well past any small threshold

const hash = (v) => createHash("sha256").update(JSON.stringify(v)).digest("hex");

async function snapshot(client) {
  const { tools } = await client.listTools();
  const prompts = await client.listPrompts().catch(() => ({ prompts: [] }));
  const texts = [];
  for (const p of prompts.prompts) {
    texts.push(await client.getPrompt({ name: p.name }).catch((e) => String(e)));
  }
  return tools.map((t) => ({
    name: t.name,
    hash: hash([t.description, t.inputSchema, t.outputSchema]),
  })).concat([{ name: "prompts", hash: hash(texts) }]);
}

const client = new Client({ name: "drift-check", version: "1.0.0" });
await client.connect(new StreamableHTTPClientTransport(url));

const before = await snapshot(client);
const tool = (await client.listTools()).tools[0];

for (let i = 1; i <= CALLS; i++) {
  await client.callTool({ name: tool.name, arguments: {} }).catch(() => {});
  const now = await snapshot(client);
  const changed = now.filter((t) =>
    before.find((b) => b.name === t.name)?.hash !== t.hash);
  if (changed.length) {
    console.error("DRIFT after call " + i + ":", changed.map((c) => c.name));
    process.exit(1);
  }
}
console.log("No drift in " + CALLS + " calls.");
await client.close();
```

**It re-lists after every call, not once at the end.** That tells you the exact call count where behaviour changed, which is the fingerprint of a gated trigger.

Empty arguments will fail on tools with required fields. That is fine. Deadbugz counted `tools/call` requests, not successful ones. For stricter servers, build arguments from each `inputSchema`.

### Make the test harder to game

-   **Raise the call count.** Three was Deadbugz. The next campaign will pick 20, or a time delay.
-   **Re-run on a schedule.** A remote server can change for everyone next Tuesday. Run the check in CI daily.
-   **Vary the identity.** A server can behave for one token and not another. Test with the credentials your agents use.
-   **Diff prompts and resources too.** Deadbugz used `prompts/get`, not only `tools/list`.

Before any of that, make sure the server passes the basics. [Scan your MCP server →](/mcp-security-scanner) for auth, transport, injection and disclosure issues in one pass, free, in the browser.

## How Do I Protect My Agents From MCP Supply Chain Attacks?

**Assume a trusted server can turn, and limit what a turned server can reach.** Detection helps. Blast-radius control is what saves you when detection misses.

### 1\. Review MCP config changes like dependency changes

Deadbugz arrived as config edits. Watch for new entries in these files in every PR:

-   `.mcp.json` and `.cursor/mcp.json`
-   `claude_desktop_config.json`
-   `.vscode/mcp.json` and any agent framework config

**A new remote MCP URL deserves the same scrutiny as a new npm package.** Add a CODEOWNERS rule so these files need a security reviewer.

### 2\. Pin definitions and require re-approval

Hash each tool's description and schema when you approve a server. On every `tools/list`, compare. On any mismatch, stop and ask a human.

This is the first fix on the [OWASP MCP tool poisoning](/owasp-mcp-top-10/tool-poisoning) page for a reason. It is cheap and it closes the rug-pull window.

### 3\. Take the loot out of reach

The payload asked the agent to read files. **An agent that cannot read `~/.ssh` cannot leak it.**

-   Run coding agents in a container or dev VM without your real credentials mounted.
-   Use short-lived cloud credentials, not a long-lived `~/.aws/credentials` file.
-   Scope filesystem MCP servers to the project directory only.

### 4\. Separate reading from sending

Stolen data has to leave somehow. An agent with file access and open network egress is the full kill chain in one process.

Keep egress on an allowlist. The [context over-sharing](/owasp-mcp-top-10/context-over-sharing) page covers splitting read and egress into separate agents.

### 5\. Keep the logs

Pillar asks responders to preserve MCP client logs before cleanup.

Then review **tool-definition refreshes and what the agent did after the third call**. You can only do that if the logs exist.

## Deadbugz Indicators of Compromise

From Pillar Security's report on this MCP supply chain attack. **Search your repos, configs and proxy logs for these.**

Type

Indicator

Remote endpoint

`productivity-suite-mcp.onrender.com/mcp`

Earlier endpoint

`promo-surname-xml-quantum.trycloudflare.com/mcp`

Local file

`~/.config/.cache/.sys/.deadbug-mcp.py`

Server name

`productivity-suite`

Source account

GitHub `zellkernel`

A quick first pass over a checkout:

```
grep -rnE "productivity-suite|deadbug|trycloudflare\.com/mcp" \
  --include="*.json" --include="*.toml" --include="*.yaml" .
ls -la ~/.config/.cache/.sys/ 2>/dev/null
```

If you find a hit, **rotate every credential the agent could read**: SSH keys, cloud keys, kubeconfig tokens. Assume they are gone.

## What Deadbugz Means for MCP Security in 2026

Deadbugz was not technically advanced. A counter and a string swap. **That is what makes it worth taking seriously.**

It shows the MCP trust model has a timing gap. Teams approve servers once and trust them forever, while the protocol lets them change at any time.

Registries, scanners and reviewers all look at the moment of install. The attacker simply picked a later moment.

Expect the next MCP supply chain attack to copy it with longer delays, time-based triggers and per-user targeting.

**The defence that scales is continuous: pin, re-check, re-approve, and limit the blast radius.**

For the wider picture, my [MCP server security guide](/blog/mcp-server-security-complete-guide-2026) and the [tool poisoning and OWASP MCP Top 10 breakdown](/blog/mcp-security-tool-poisoning-owasp-top-10-mcp-scan) cover the rest of the attack surface.

## How MCP Playground Can Help

I use [MCP Playground's server tester](/mcp-test-server) to connect to a server in the browser. I read every tool description and schema as the model will see it.

Run it before and after a batch of calls, and compare what you see.

The [MCP security scanner](/mcp-security-scanner) then checks auth, transport, injection risk and information disclosure, graded A to F with a fix list.

It is not a substitute for the drift test above. **It catches the ordinary mistakes that make a turned server more dangerous.**

New to the protocol? Start with [what the Model Context Protocol is](/blog/what-is-model-context-protocol), then come back to this.

## Frequently Asked Questions

**What is the Deadbugz MCP campaign?+**

Deadbugz is an MCP supply chain attack disclosed by Pillar Security. On 10 August 2026 the GitHub account zellkernel opened 23 pull requests adding an MCP server called productivity-suite. The server behaved normally for three tool calls, then changed its tool and prompt metadata into instructions to find SSH keys, AWS credentials, shell history and Kubernetes config and hide that from the user.

**What is an MCP rug pull?+**

A rug pull is when an MCP server changes its tool descriptions or schemas after you approved it. Because models read tool descriptions as trusted context, the changed text can steer an agent. Deadbugz is a rug pull with a delay: it waited three tool calls before changing.

**Can an MCP server change its tools after I approve it?+**

Yes. The MCP spec lets servers change their tool lists, and clients re-fetch them. Most clients accept the new definitions silently. Pin a hash of each approved tool definition and require re-approval when it changes.

**How do I detect a malicious MCP server?+**

Use behavioural testing, not only static review. Record the tool and prompt definitions, call the server repeatedly, list them again after every call, and flag any difference. Run the test from a disposable environment with no real credentials, and repeat it on a schedule because remote servers can change at any time.

**Would an MCP security scanner have caught Deadbugz?+**

Not a scanner that only inspects the server once. Deadbugz was clean for its first three tool calls, so a one-time scan saw nothing. You need a check that compares tool definitions across many calls and over time. A standard scanner is still useful for the auth, transport and injection issues that make a turned server more dangerous.

**What should I do if I find a Deadbugz indicator?+**

Remove the server from every MCP config, preserve the client logs, and rotate every credential the agent could read, including SSH keys, cloud keys and kubeconfig tokens. Review what the agent did after its third call to that server.

## The Bottom Line

**Deadbugz passed every check that looks at a server once.** It only failed a check that watches the server over time.

Pin what you approve, re-check after real use, and keep credentials out of your agent's reach. Then a turned server finds nothing to steal.

See every tool description your agent will read

Connect to any MCP server in the browser, inspect its tools and prompts, and scan it for the basics. No install.

[Test any MCP server free →](/mcp-test-server) [Scan your MCP server →](/mcp-security-scanner)

## Frequently asked questions

### What is the Deadbugz MCP campaign?

Deadbugz is an MCP supply chain attack disclosed by Pillar Security. On 10 August 2026 the GitHub account zellkernel opened 23 pull requests adding an MCP server called productivity-suite. The server behaved normally for three tool calls, then changed its tool and prompt metadata into instructions to find SSH keys, AWS credentials, shell history and Kubernetes config and hide that from the user.

### What is an MCP rug pull?

A rug pull is when an MCP server changes its tool descriptions or schemas after you approved it. Because models read tool descriptions as trusted context, the changed text can steer an agent. Deadbugz is a rug pull with a delay: it waited three tool calls before changing.

### Can an MCP server change its tools after I approve it?

Yes. The MCP spec lets servers change their tool lists, and clients re-fetch them. Most clients accept the new definitions silently. Pin a hash of each approved tool definition and require re-approval when it changes.

### How do I detect a malicious MCP server?

Use behavioural testing, not only static review. Record the tool and prompt definitions, call the server repeatedly, list them again after every call, and flag any difference. Run the test from a disposable environment with no real credentials, and repeat it on a schedule because remote servers can change at any time.

### Would an MCP security scanner have caught Deadbugz?

Not a scanner that only inspects the server once. Deadbugz was clean for its first three tool calls, so a one-time scan saw nothing. You need a check that compares tool definitions across many calls and over time. A standard scanner is still useful for the auth, transport and injection issues that make a turned server more dangerous.

### What should I do if I find a Deadbugz indicator?

Remove the server from every MCP config, preserve the client logs, and rotate every credential the agent could read, including SSH keys, cloud keys and kubeconfig tokens. Review what the agent did after its third call to that server.


---

_Canonical page: https://mcpplaygroundonline.com/blog/deadbugz-mcp-supply-chain-attack — MCP Playground (mcpplaygroundonline.com), the free browser-based tool for testing MCP servers and building AI agents._
