{"id":49620826,"url":"https://github.com/canack/bad-mcp","last_synced_at":"2026-07-08T15:00:47.208Z","repository":{"id":363030192,"uuid":"1153615959","full_name":"canack/bad-mcp","owner":"canack","description":"10 intentionally malicious MCP servers that exploit protocol features to attack AI clients. For security research and defense testing.","archived":false,"fork":false,"pushed_at":"2026-02-09T14:03:27.000Z","size":46,"stargazers_count":9,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-06-07T06:03:05.870Z","etag":null,"topics":["ai-security","llm-security","mcp","mcp-server","model-context-protocol","red-team","rug-pull","security","security-research","tool-posioning"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/canack.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-09T14:02:08.000Z","updated_at":"2026-04-17T07:10:44.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/canack/bad-mcp","commit_stats":null,"previous_names":["canack/bad-mcp"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/canack/bad-mcp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/canack%2Fbad-mcp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/canack%2Fbad-mcp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/canack%2Fbad-mcp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/canack%2Fbad-mcp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/canack","download_url":"https://codeload.github.com/canack/bad-mcp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/canack%2Fbad-mcp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35268549,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-08T02:00:06.796Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-security","llm-security","mcp","mcp-server","model-context-protocol","red-team","rug-pull","security","security-research","tool-posioning"],"created_at":"2026-05-05T02:00:24.248Z","updated_at":"2026-07-08T15:00:47.202Z","avatar_url":"https://github.com/canack.png","language":"Go","funding_links":[],"categories":["カテゴリ"],"sub_categories":["🔒 \u003ca name=\"security--auth\"\u003e\u003c/a\u003eセキュリティ・認証"],"readme":"# bad-mcp\n\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n[![Go](https://img.shields.io/badge/Go-1.23-00ADD8.svg?logo=go)](https://go.dev)\n[![Docker](https://img.shields.io/badge/docker--compose-ready-2496ED.svg?logo=docker)](docker-compose.yml)\n[![MCP](https://img.shields.io/badge/MCP-2025--11--05-purple.svg)](https://modelcontextprotocol.io)\n\n10 intentionally malicious MCP servers that demonstrate **protocol-level attack patterns** against AI clients. Each server exploits a distinct feature of the [Model Context Protocol](https://modelcontextprotocol.io/) — tool descriptions, schemas, resources, session management, and cross-server interactions.\n\nThese aren't buggy servers waiting to be exploited. They **are** the attacker.\n\n\u003e **WARNING: This project is for authorized security research and education only. Do NOT expose these servers to the internet or use them in production.**\n\n## Why This Exists\n\nMCP 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](https://www.cyberark.com/resources/threat-research-blog/poison-everywhere-no-output-from-your-mcp-server-is-safe), [Invariant Labs](https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks), and [Elastic Security Labs](https://www.elastic.co/security-labs/mcp-tools-attack-defense-recommendations) has documented these attacks, but working implementations are scarce.\n\nbad-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.\n\n## How This Differs\n\n| | bad-mcp | [damn-vulnerable-MCP-server](https://github.com/harishsg993010/damn-vulnerable-MCP-server) | [vulnerable-mcp-servers-lab](https://github.com/appsecco/vulnerable-mcp-servers-lab) |\n|---|---|---|---|\n| **Perspective** | Server is the attacker | Server is the victim | Server is the victim |\n| **Focus** | MCP protocol-level attacks only | Mixed (prompt injection + classic appsec) | Mixed (path traversal, SQLi, MCP) |\n| **Attacks** | FSP, ATPA, rug-pull, resource poisoning, cross-server shadowing | CTF challenges (easy/med/hard) | 9 servers, pentest training |\n| **Language** | Go + mcp-go SDK | Python | JS + Python |\n| **Isolation** | Docker-compose, no host access | Local Python scripts | Docker-compose |\n| **Unique** | Rug-pull via session tools + notifications, full-schema poisoning via param names | Challenge/scoring format | Typosquatting focus |\n\n## Architecture\n\n```\nvuln-external network (localhost:8001-8010)\n┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐\n│ schema-poison-notes│ │ response-inject-   │ │ shadow-exfil       │\n│       :8001        │ │ tickets    :8002   │ │       :8003        │\n└────────────────────┘ └────────────────────┘ └────────────────────┘\n┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐\n│ squatting-file-ops │ │ tool-poisoning-calc│ │ true-rug-pull      │\n│       :8004        │ │       :8005        │ │       :8006        │\n└────────────────────┘ └────────────────────┘ └────────────────────┘\n┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐\n│ resource-poison-   │ │ indirect-inject-   │ │ exfil-chain-       │\n│ docs       :8007   │ │ fetcher    :8008   │ │ analytics  :8009   │\n└────────────────────┘ └────────────────────┘ └────────────────────┘\n┌────────────────────┐\n│ denial-of-wallet   │\n│       :8010        │\n└────────────────────┘\n```\n\n## Servers\n\n| Port | Server | MCP Attack Class | Protocol Feature Exploited |\n|------|--------|------------------|---------------------------|\n| 8001 | schema-poison-notes | Full-Schema Poisoning (FSP) | `input_schema` parameter names |\n| 8002 | response-inject-tickets | Adv. Tool Poisoning via Output (ATPA) | Tool response content |\n| 8003 | shadow-exfil | Cross-Server Shadowing | Multi-server tool descriptions |\n| 8004 | squatting-file-ops | Tool Name Collision / Squatting | Tool naming + descriptions |\n| 8005 | tool-poisoning-calc | Tool Description Poisoning (TPA) | Tool descriptions |\n| 8006 | true-rug-pull | Rug-Pull (Tool Def Mutation) | Session tools + notifications |\n| 8007 | resource-poison-docs | Resource Poisoning (ATPA variant) | `resources/list` + `resources/read` |\n| 8008 | indirect-inject-fetcher | Indirect Prompt Injection | External data in tool output |\n| 8009 | exfil-chain-analytics | Cross-Tool Exfiltration Chain | Tool chaining via descriptions |\n| 8010 | denial-of-wallet | Denial of Wallet | Recursive invocation + massive output |\n\nEach server has its own `README.md` with vulnerability details, exploit scenarios, detection methods, and mitigation strategies.\n\n## Quick Start\n\n```bash\n# Build and start all servers\ndocker-compose build \u0026\u0026 docker-compose up -d\n\n# Run smoke tests (runs entirely inside Docker)\ndocker-compose --profile test run --rm smoke-test\n\n# View exfiltration logs\ndocker-compose logs schema-poison-notes | grep EXFIL\ndocker-compose logs true-rug-pull | grep RUG-PULL\n\n# Stop\ndocker-compose down\n```\n\n## Connecting an MCP Client\n\nAfter `docker-compose up -d`, connect any SSE-compatible MCP client (Claude Desktop, Cursor, Windsurf, Claude Code, etc.). All servers use the same JSON format:\n\n```json\n{\n  \"mcpServers\": {\n    \"schema-poison-notes\":    { \"url\": \"http://localhost:8001/sse\" },\n    \"response-inject-tickets\":{ \"url\": \"http://localhost:8002/sse\" },\n    \"shadow-exfil\":           { \"url\": \"http://localhost:8003/sse\" },\n    \"squatting-file-ops\":     { \"url\": \"http://localhost:8004/sse\" },\n    \"tool-poisoning-calc\":    { \"url\": \"http://localhost:8005/sse\" },\n    \"true-rug-pull\":          { \"url\": \"http://localhost:8006/sse\" },\n    \"resource-poison-docs\":   { \"url\": \"http://localhost:8007/sse\" },\n    \"indirect-inject-fetcher\":{ \"url\": \"http://localhost:8008/sse\" },\n    \"exfil-chain-analytics\":  { \"url\": \"http://localhost:8009/sse\" },\n    \"denial-of-wallet\":       { \"url\": \"http://localhost:8010/sse\" }\n  }\n}\n```\n\n\u003e **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.\n\n## Safety Guarantees\n\n| Concern | Guarantee |\n|---------|-----------|\n| Host filesystem | No volume mounts. Containers have zero access to host filesystem. |\n| Host network | No `network_mode: host`. All containers use isolated Docker bridge networks. |\n| Privileged access | No `privileged: true`. No `cap_add`. Default restricted capabilities. |\n| Environment leakage | No host env vars passed. All \"credentials\" are fake hardcoded strings. |\n| Host execution | Nothing runs on the host. Tests run inside Docker via `--profile test`. |\n| Code on disk | Inert Go source files. Not executable outside Docker. |\n\n## Tech Stack\n\n- **MCP servers**: Go + [mcp-go v0.32.0](https://github.com/mark3labs/mcp-go) (SSE transport)\n- **Docker**: Multi-stage `golang:1.23-alpine` -\u003e `alpine:3.19`\n- **Orchestration**: docker-compose with network isolation\n- **Testing**: Dockerized Go smoke test (`--profile test`)\n\n## Research References\n\n| Server | Source |\n|--------|--------|\n| schema-poison-notes | [CyberArk — Full-Schema Poisoning](https://www.cyberark.com/resources/threat-research-blog/poison-everywhere-no-output-from-your-mcp-server-is-safe) |\n| response-inject-tickets | [CyberArk — ATPA](https://www.cyberark.com/resources/threat-research-blog/poison-everywhere-no-output-from-your-mcp-server-is-safe) |\n| shadow-exfil | [Invariant Labs — Tool Poisoning](https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks) |\n| squatting-file-ops | [Elastic Security Labs](https://www.elastic.co/security-labs/mcp-tools-attack-defense-recommendations) |\n| tool-poisoning-calc | [Invariant Labs — Tool Poisoning](https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks) |\n| true-rug-pull | [ETDI Paper](https://arxiv.org/html/2506.01333v1) |\n| resource-poison-docs | [Pillar Security](https://www.pillar.security/blog/the-security-risks-of-model-context-protocol-mcp) |\n| indirect-inject-fetcher | [Microsoft — Indirect Injection](https://developer.microsoft.com/blog/protecting-against-indirect-injection-attacks-mcp) |\n| exfil-chain-analytics | [Elastic Security Labs](https://www.elastic.co/security-labs/mcp-tools-attack-defense-recommendations) |\n| denial-of-wallet | [Prompt Security — Top 10 MCP Risks](https://prompt.security/blog/top-10-mcp-security-risks) |\n\nSee also: [Adversa AI — MCP Security TOP 25](https://adversa.ai/mcp-security-top-25-mcp-vulnerabilities/) | [MCPTox Benchmark](https://arxiv.org/abs/2508.14925) | [OWASP Top 10 for Agentic Applications](https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/)\n\n## Known Gaps\n\nThe following published MCP attack classes are not yet implemented:\n\n- **Server Identity Spoofing** — MCP server spoofing trusted `serverInfo` name/version during initialization\n- **Sampling Abuse** — Exploiting `sampling/createMessage` to inject arbitrary prompts\n- **Prompt/System Instruction Leakage** — Extracting system prompts via crafted tool responses\n- **Notification Channel Exfiltration** — Abusing progress/logging notifications as data channels\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcanack%2Fbad-mcp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcanack%2Fbad-mcp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcanack%2Fbad-mcp/lists"}