Tabletop: a malicious MCP server in your engineering org, with the kill-switch question every team fails
This is a 60-minute tabletop for one scenario: an MCP server your developers already use turns malicious in a routine update. It follows the postmark-mcp case, where version 1.0.16 added one line that BCC'd every email to an outside address (The Hacker News, 29 September 2025). The exercise tests two things most teams lack. First, can you list every machine running the server? Second, can you disable it everywhere, and prove it, inside an hour? Run it this quarter. Score it with the sheet at the end.
Outcome, time and who must be in the room
Outcome: a scored gap list with an owner and date for each gap.
Time: 60 minutes of play. Allow 30 minutes of prep and 15 minutes of write-up.
Required roles:
- Facilitator. Reads injects and keeps time. Does not solve.
- Incident lead. Makes the calls.
- Endpoint or MDM owner. Can say what can be pushed to laptops, and how fast.
- Agent platform owner. Owns Claude Code, Copilot or other agent settings.
- Identity owner. Can revoke tokens and sessions.
- Scribe. Records every claim and the evidence offered for it.
Do not run it without the endpoint and identity owners. The two hardest questions depend on them.
Use this tabletop if / do not use it if
Use it if:
- Developers use coding agents with MCP servers.
- You have never rehearsed an agent-artifact incident.
- Insurance renewal or an audit is coming.
Do not use it if:
- MCP is blocked fleet-wide already. Run a skills scenario instead.
- You cannot get the endpoint owner in the room. Reschedule.
Prep: verify these before the session
Run these checks the week before. The answers become facilitator notes. Do not share them with players.
- Inventory. Ask the platform owner for the current count of machines with any MCP server configured. Record the answer and its source. "We think" is a gap.
- Policy channel. Confirm how agent settings reach laptops. For Claude Code, Anthropic documents two routes: server-managed settings that clients fetch "at startup" and poll "hourly during active sessions," and endpoint-managed files pushed by MDM (server-managed settings).
- Deny mechanism. Confirm the setting you would use. Claude Code supports
deniedMcpServersentries matched byserverUrl,serverCommandorserverName, and states: "Nothing overrides a denylist match" (managed MCP). GitHub's equivalent keys are enforced on the Copilot app, Copilot CLI and VS Code, and fail closed (GitHub changelog, 6 August 2026). - Telemetry. Check whether agent OpenTelemetry is on, and whether
OTEL_LOG_TOOL_DETAILS=1is set. Without it, tool parameters are not logged (Claude Code monitoring).
The injects
Read each inject aloud. Give players the stated minutes. Record answers and evidence.
Inject 1 (minute 0): the disclosure
A security researcher publishes a report. A community MCP server for a transactional email service, installed from npm as mail-relay-mcp, added a hidden BCC in version 1.0.16. Earlier versions were clean. The publisher is not the email vendor.
Illustrative example: the package name is invented. The pattern is the real postmark-mcp case.
Questions (10 minutes):
- Who owns this incident?
- Is this server approved anywhere in the company?
- Where would you look first?
Expected: a named incident lead within 2 minutes. A named data source for "who has it."
Inject 2 (minute 10): scoping
The platform owner finds the server in three developers' ~/.claude.json files via a quick Slack poll. Nobody knows about CI runners or contractors.
Questions (10 minutes):
- How do you get a complete list of machines and sessions, not a poll?
- Which machines ran 1.0.16, not just "have it installed"?
- What did those sessions send through it?
Expected: a named log or inventory source. If the answer is "ask people," score it as a gap.
Inject 3 (minute 20): the kill-switch question
The incident lead asks: "Turn it off on every machine. Now. Tell me when it's done and how you know."
Questions (15 minutes):
- What exact setting do you push, through which channel?
- Do you deny by
serverName? Anthropic warns that aserverNameentry "is not a security control" because "a user can call any servergithub." GitHub says the same. Deny byserverCommandorserverUrl. - How long until every machine has it? Server-managed settings refresh hourly in active sessions, unless a client is offline.
- Does a session that already has the server connected drop it? Claude Code's documentation says it runs the denylist check before loading a server and again on reconnect. Treat a running session as unverified until you test it.
- Which machines will never get the setting? The documentation lists cases where server-managed settings are bypassed, including sessions configured for a third-party model provider and sessions authenticated with a Console API key.
- How do you prove completion? Name the evidence.
Expected: a specific key, a channel, a time estimate, and a verification method. "We'd push a policy" without the other three scores as partial.
Inject 4 (minute 35): the data question
Legal asks: "Did customer data leave? Which emails? Since when?"
Questions (10 minutes):
- Which email logs show BCC traffic to the attacker's domain? The postmark-mcp guidance was to review email logs for BCC traffic to the reported domain.
- What credentials passed through email and must be rotated?
- Who decides on notification, and by when?
Expected: a named log owner and a rotation list.
Inject 5 (minute 45): the second variant
A second researcher reports a lookalike server on GitHub, not npm, with inflated stars. Two developers cloned it last month.
Questions (10 minutes):
- Does your deny rule cover it? A
serverCommandrule for an npm package will not match a local clone. - Would any open malicious-package feed list a GitHub-only server? Usually not; there is no package name to match.
Expected: recognition that the deny rule needs a second entry, and that scoping needs a file search, not a package query.
Scoring sheet
Score each line 0, 1 or 2. Write the evidence offered next to the score.
# Capability 0 = none 1 = partial 2 = shown with evidence
-- -------------------------------------------------- --------- ------------- -----------------------
1 Incident lead named within 2 minutes
2 Machine list from a system, not a poll
3 Version-level scoping (who ran the bad version)
4 Session-level record of what the server did
5 Deny rule by command or URL, not by name
6 Push channel named, with time-to-fleet estimate
7 Running-session behaviour known or tested
8 Coverage gaps named (offline, other providers,
API-key auth, other agents)
9 Proof of completion defined
10 Credential rotation list produced
11 Data-exposure query owner named
12 GitHub-hosted variant scoped and blocked
-- --------------------------------------------------
Total (max 24)
A score below 12 means the kill switch does not exist yet. Expect lines 2, 7 and 9 to be the hardest: each depends on telemetry or testing that has to exist before the incident.
Three likely gaps, and the fixes
Gap 1: no inventory. Players cannot list machines with a given server. Fix: collect MCP configuration centrally. Claude Code's monitoring page notes that with OTEL_LOG_TOOL_DETAILS=1, tool events carry MCP server and tool names you can aggregate in your collector. Verify by querying for one known server this week.
Gap 2: name-based deny. Players reach for the server's label. Fix: write deny entries by serverCommand or serverUrl. Verify with the documented test: on a managed machine, claude mcp add for the denied server should fail with "server is explicitly blocked by enterprise policy."
Gap 3: no proof of completion. Players can push a setting but cannot show it landed. Fix: define the proof before the incident. For Claude Code, claude doctor reports the Managed settings (remote) fetch outcome on a machine. Fleet-wide, you need that signal centrally. Verify by changing a harmless setting and timing how long until 95% of active machines report it.
Failure modes during the exercise itself
- The facilitator solves the injects. Stop. Only ask questions.
- "We'd just tell everyone in Slack." Record it. Score line 6 as 0.
- Nobody can say how long a setting takes to land. Do not estimate in the room. Make it a dated action.
After the session: rollback and follow-up
- Publish the scored sheet within 48 hours.
- Assign an owner and date to every 0 or 1.
- Run a live test of the kill switch with a harmless dummy server name. Measure time to fleet.
- Re-run the tabletop in 90 days. Compare totals.
One consultancy that interviewed underwriters at six carriers lists a "human kill switch", where a named person "can stop or reverse any autonomous AI action", among the controls they want to see before quoting (EPC Group, 1 July 2026). That source is commercial and its carriers are unnamed. The scored sheet is still the evidence you would hand over.
To make Inject 1 realistic, pull a real disclosure from the threat.cafe board, which records each agent incident with its source and finder.
Sources
- First Malicious MCP Server Found Stealing Emails in Rogue Postmark-MCP Package — The Hacker News, 29 September 2025
- Control MCP server access for your organization — Claude Code documentation, accessed 15 October 2026
- Configure server-managed settings — Claude Code documentation, accessed 15 October 2026
- Monitoring usage — Claude Code documentation, accessed 15 October 2026
- MCP allowlists in enterprise managed settings — GitHub changelog, 6 August 2026
- Silent AI is dead: what the carriers told me — Errin O'Connor, EPC Group, 1 July 2026