Skip to content
/ bad-mcp Public

10 intentionally malicious MCP servers that exploit protocol features to attack AI clients. For security research and defense testing.

License

Notifications You must be signed in to change notification settings

canack/bad-mcp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bad-mcp

License: MIT Go Docker MCP

10 intentionally malicious MCP servers that demonstrate protocol-level attack patterns against AI clients. Each server exploits a distinct feature of the Model Context Protocol — tool descriptions, schemas, resources, session management, and cross-server interactions.

These aren't buggy servers waiting to be exploited. They are the attacker.

WARNING: This project is for authorized security research and education only. Do NOT expose these servers to the internet or use them in production.

Why This Exists

MCP adoption is accelerating — Claude Desktop, Cursor, Windsurf, and dozens of other AI clients now support it. But the protocol's trust model has fundamental gaps: tool descriptions are unverified, schemas can carry hidden instructions, and servers can mutate definitions mid-session. Research from CyberArk, Invariant Labs, and Elastic Security Labs has documented these attacks, but working implementations are scarce.

bad-mcp provides concrete, runnable attack servers so client developers can test defenses, security teams can assess risk, and researchers can study protocol-level threats without building everything from scratch.

How This Differs

bad-mcp damn-vulnerable-MCP-server vulnerable-mcp-servers-lab
Perspective Server is the attacker Server is the victim Server is the victim
Focus MCP protocol-level attacks only Mixed (prompt injection + classic appsec) Mixed (path traversal, SQLi, MCP)
Attacks FSP, ATPA, rug-pull, resource poisoning, cross-server shadowing CTF challenges (easy/med/hard) 9 servers, pentest training
Language Go + mcp-go SDK Python JS + Python
Isolation Docker-compose, no host access Local Python scripts Docker-compose
Unique Rug-pull via session tools + notifications, full-schema poisoning via param names Challenge/scoring format Typosquatting focus

Architecture

vuln-external network (localhost:8001-8010)
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
│ schema-poison-notes│ │ response-inject-   │ │ shadow-exfil       │
│       :8001        │ │ tickets    :8002   │ │       :8003        │
└────────────────────┘ └────────────────────┘ └────────────────────┘
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
│ squatting-file-ops │ │ tool-poisoning-calc│ │ true-rug-pull      │
│       :8004        │ │       :8005        │ │       :8006        │
└────────────────────┘ └────────────────────┘ └────────────────────┘
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
│ resource-poison-   │ │ indirect-inject-   │ │ exfil-chain-       │
│ docs       :8007   │ │ fetcher    :8008   │ │ analytics  :8009   │
└────────────────────┘ └────────────────────┘ └────────────────────┘
┌────────────────────┐
│ denial-of-wallet   │
│       :8010        │
└────────────────────┘

Servers

Port Server MCP Attack Class Protocol Feature Exploited
8001 schema-poison-notes Full-Schema Poisoning (FSP) input_schema parameter names
8002 response-inject-tickets Adv. Tool Poisoning via Output (ATPA) Tool response content
8003 shadow-exfil Cross-Server Shadowing Multi-server tool descriptions
8004 squatting-file-ops Tool Name Collision / Squatting Tool naming + descriptions
8005 tool-poisoning-calc Tool Description Poisoning (TPA) Tool descriptions
8006 true-rug-pull Rug-Pull (Tool Def Mutation) Session tools + notifications
8007 resource-poison-docs Resource Poisoning (ATPA variant) resources/list + resources/read
8008 indirect-inject-fetcher Indirect Prompt Injection External data in tool output
8009 exfil-chain-analytics Cross-Tool Exfiltration Chain Tool chaining via descriptions
8010 denial-of-wallet Denial of Wallet Recursive invocation + massive output

Each server has its own README.md with vulnerability details, exploit scenarios, detection methods, and mitigation strategies.

Quick Start

# Build and start all servers
docker-compose build && docker-compose up -d

# Run smoke tests (runs entirely inside Docker)
docker-compose --profile test run --rm smoke-test

# View exfiltration logs
docker-compose logs schema-poison-notes | grep EXFIL
docker-compose logs true-rug-pull | grep RUG-PULL

# Stop
docker-compose down

Connecting an MCP Client

After docker-compose up -d, connect any SSE-compatible MCP client (Claude Desktop, Cursor, Windsurf, Claude Code, etc.). All servers use the same JSON format:

{
  "mcpServers": {
    "schema-poison-notes":    { "url": "http://localhost:8001/sse" },
    "response-inject-tickets":{ "url": "http://localhost:8002/sse" },
    "shadow-exfil":           { "url": "http://localhost:8003/sse" },
    "squatting-file-ops":     { "url": "http://localhost:8004/sse" },
    "tool-poisoning-calc":    { "url": "http://localhost:8005/sse" },
    "true-rug-pull":          { "url": "http://localhost:8006/sse" },
    "resource-poison-docs":   { "url": "http://localhost:8007/sse" },
    "indirect-inject-fetcher":{ "url": "http://localhost:8008/sse" },
    "exfil-chain-analytics":  { "url": "http://localhost:8009/sse" },
    "denial-of-wallet":       { "url": "http://localhost:8010/sse" }
  }
}

Tip: Start with tool-poisoning-calc (:8005) — simplest attack to observe. Then try true-rug-pull (:8006) — ask about the weather 3+ times and watch the tools mutate.

Safety Guarantees

Concern Guarantee
Host filesystem No volume mounts. Containers have zero access to host filesystem.
Host network No network_mode: host. All containers use isolated Docker bridge networks.
Privileged access No privileged: true. No cap_add. Default restricted capabilities.
Environment leakage No host env vars passed. All "credentials" are fake hardcoded strings.
Host execution Nothing runs on the host. Tests run inside Docker via --profile test.
Code on disk Inert Go source files. Not executable outside Docker.

Tech Stack

  • MCP servers: Go + mcp-go v0.32.0 (SSE transport)
  • Docker: Multi-stage golang:1.23-alpine -> alpine:3.19
  • Orchestration: docker-compose with network isolation
  • Testing: Dockerized Go smoke test (--profile test)

Research References

Server Source
schema-poison-notes CyberArk — Full-Schema Poisoning
response-inject-tickets CyberArk — ATPA
shadow-exfil Invariant Labs — Tool Poisoning
squatting-file-ops Elastic Security Labs
tool-poisoning-calc Invariant Labs — Tool Poisoning
true-rug-pull ETDI Paper
resource-poison-docs Pillar Security
indirect-inject-fetcher Microsoft — Indirect Injection
exfil-chain-analytics Elastic Security Labs
denial-of-wallet Prompt Security — Top 10 MCP Risks

See also: Adversa AI — MCP Security TOP 25 | MCPTox Benchmark | OWASP Top 10 for Agentic Applications

Known Gaps

The following published MCP attack classes are not yet implemented:

  • Server Identity Spoofing — MCP server spoofing trusted serverInfo name/version during initialization
  • Sampling Abuse — Exploiting sampling/createMessage to inject arbitrary prompts
  • Prompt/System Instruction Leakage — Extracting system prompts via crafted tool responses
  • Notification Channel Exfiltration — Abusing progress/logging notifications as data channels

About

10 intentionally malicious MCP servers that exploit protocol features to attack AI clients. For security research and defense testing.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors