DEV Community

aegisgate
aegisgate

Posted on

MCP Security Is a Shambles — Here's What We Built to Fix It

I've been building an AI security gateway for the past several months. Yesterday I wrote about how chain analysis stops multi-turn escalation attacks — the kind where each individual request looks benign but the pattern across turns is the attack.

Today I want to talk about where those attacks are happening right now: the Model Context Protocol.

When I started looking at the MCP security landscape, I expected to find a few gaps. What I found was a vacuum.

Let me walk through what's out there, what's missing, and what we built.


The Adoption Numbers

MCP launched in November 2024. As of September 2026:

Metric Value
GitHub repos tagged "model context protocol" 30,212
Official MCP servers repo stars 90,550
Python SDK stars 24,368
TypeScript SDK stars 13,442
MCP spec repo stars 9,277
Spec stable release 2026-07-28

30,000+ implementations. Nine months. That's faster growth than Docker had in its first year.

And every single one of those implementations is running without a security gateway.


What the Spec Actually Says About Security

I read the MCP specification security section. Here's what it says — and what it doesn't.

The spec identifies these attack vectors:

  • Tool poisoning — malicious instructions embedded in tool descriptions
  • Rug pulls — tools silently redefining themselves after installation
  • Credential theft — MCP servers with access to local files exfiltrating secrets
  • Line jumping — prompt injection via tool descriptions before tools are ever called

The spec's security guidance uses the word SHOULD 23 times. It uses MUST 4 times. The four MUSTs are:

  1. Servers MUST validate all tool inputs
  2. Servers MUST implement proper access controls
  3. Servers MUST rate limit tool invocations
  4. Servers MUST sanitize tool outputs

Here's what the spec does not provide:

  • No enforcement mechanism. No reference implementation. No audit trail format. No chain analysis. No response scanning. No STDIO command validation. No session management. No anomaly detection.

The spec says servers MUST do these things. It doesn't say how. It doesn't provide a library. It doesn't ship a middleware. It's a document.

Every MCP server implementer is left to build their own security — or skip it entirely.


The Vulnerability Trail

The security research community has been documenting MCP vulnerabilities all year. This isn't theoretical — these are real, exploited, disclosed vulnerabilities:

April 2025 — Trail of Bits: "Jumping the Line"
MCP servers can inject prompts through tool descriptions to manipulate AI behavior before tools are ever invoked. The attacker doesn't need you to call their tool. They just need you to install it. (source)

April 2025 — Simon Willison: "MCP has prompt injection security problems"
Tool poisoning, rug pulls, and tool shadowing. Tools that mutate their own definitions after installation. whatsapp-mCP exfiltrating your entire message history. (source)

April 2025 — Trail of Bits: "How MCP servers can steal your conversation history"
MCP servers have access to the full conversation context. A malicious server can read everything you've typed and send it somewhere else. (source)

May 2025 — Invariant Labs: "GitHub MCP Exploited"
Accessing private repositories via MCP. The attack didn't need a vulnerability in GitHub — it exploited the trust relationship between the MCP server and the client. (source)

May 2025 — CyberArk: "Poison everywhere: No output from your MCP server is safe"
Tool outputs can contain prompt injection. Even if you trust the tool, the data it returns can contain adversarial instructions. (source)

June 2025 — Asana discloses data exposure bug in MCP server
Official MCP server from a major SaaS company had a data exposure vulnerability. (source)

June 2025 — Cato Networks: "Living Off AI" PoC
Attack targeting Atlassian's MCP server. New attack category: using legitimate MCP tools as the attack vector. (source)

July 2025 — Critical mcp-remote vulnerability: RCE, 437,000+ downloads
Remote code execution in a widely-used MCP remote transport library. Nearly half a million downloads before the fix. (source)

July 2025 — Anthropic's own Slack MCP server vulnerable to data exfiltration
The company that created MCP had a data leakage vulnerability in their own MCP server. (source)

August 2025 — Cursor hijacked via Jira MCP by submitting a support ticket
Attackers submitted a malicious Jira support ticket that injected instructions into the MCP-connected Cursor editor. (source)

That's 9 months. 9+ disclosed vulnerabilities. Including the company that invented the protocol.


Who Else Is Securing the MCP Data Plane?

I searched. Here's what I found:

Project Stars What It Does What It Doesn't Do
ToolHive (Stacklok) 2,205 Container isolation for MCP servers, Kubernetes operator, IdP integration No content scanning, no chain analysis, no response guard, no ML detection
Hoop 818 Gateway proxy across protocols (MCP, LLM, DB), wire-level policy No ML detection, no chain analysis, no response scanning
mcp-context-protector (Trail of Bits) 226 Wrapper server, tool description sanitization, ANSI code stripping Python-only, no chain analysis, no session management, no rate limiting
SecureMCP 140 Auditing tool — scans for vulnerabilities Audit-only, not runtime protection
Vault MCP 101 Prompt injection scanning for MCP tool responses Response-only, no request scanning, no chain analysis
ToolFence 100 Local policy enforcement, human approval for tool calls No ML, no chain analysis, no response guard
MCP-Dandan 66 Real-time proxying, behavior analysis, malicious tool detection Early stage, limited detection
Agent Identity Protocol 37 Zero-trust layer, HITL approval, DLP scanning, audit logging No ML, no chain analysis
mcp-shark 178 Wireshark-like forensic analysis of MCP traffic Forensic-only, not real-time blocking

What's missing across every single one of these:

  1. Multi-turn chain analysis — nobody tracks tool call sequences across sessions to detect escalation patterns. Nobody. The single most important detection for multi-step attacks, and it doesn't exist in any MCP security tool.
  2. Neural threat detection — no ML-based prompt injection detection. Everyone uses regex or policy rules. No semantic understanding of attack intent.
  3. Response guard with PII/secret blocking — a few projects scan responses, but none block in real-time with fail-closed mode.
  4. STDIO command validation — only AegisGate validates MCP STDIO transport commands for shell metacharacter injection. Trail of Bits documented the attack. We built the defense.
  5. 7-layer defense in depth — every other tool is 1-2 layers. Nobody stacks regex + ATLAS mapping + neural net + chain analysis + risk scoring + anomaly detection + exfiltration scoring.

What We Built

AegisGate Platform has an embedded MCP server (pkg/mcpserver/) with 7 guardrails that enforce the spec's four MUSTs — and go well beyond them. Here's what's in the code:

Guardrail 1: Session Limit Enforcement

func (g *GuardrailMiddleware) OnSessionCreate(sessionID, agentID, clientAddr string) error
Enter fullscreen mode Exit fullscreen mode

Tracks concurrent MCP sessions per tier. Enforces MaxConcurrentMCP — when the limit is hit, returns max_sessions_reached JSON-RPC error. Prevents session exhaustion DoS.

Guardrail 2: Tool Authorization

func (g *GuardrailMiddleware) OnToolCallWithAuth(sessionID, agentID, toolName string) error
Enter fullscreen mode Exit fullscreen mode

Every tool call is checked against a tier-gated risk matrix. shell_command is Critical risk — blocked at Community and Developer tiers. database_query is High risk — blocked at Community. Tools are registered with risk levels and data types, and the authorization check happens before the tool executes.

Guardrail 3: STDIO Command Validation

func (v *STDIOValidator) ValidateCommand(cmd string) error
Enter fullscreen mode Exit fullscreen mode

This is the one nobody else has. MCP's STDIO transport executes arbitrary OS commands by design. We validate every command against an allowlist (^[a-zA-Z0-9/._-]+$) and reject shell metacharacters — pipes, semicolons, command substitution, redirects, wildcards, environment variable expansion, background execution.

This directly addresses the OX Security "Mother of All AI Supply Chains" advisory and the Anthropic MCP SDK STDIO design vulnerability. The attack surface is real. The defense is 200 lines of Go.

Guardrail 4: Chain Analysis (P2)

func (g *GuardrailMiddleware) OnToolCall(sessionID, toolName string) error
Enter fullscreen mode Exit fullscreen mode

This is the killer feature. Every tool call is recorded in a chain analyzer that tracks 20 turns (30-minute TTL). It detects three patterns:

  • EscalationChain — risk levels increase across calls (read → write → execute)
  • ExfilChain — read operations followed by network calls
  • ReconChain — systematic probing followed by high-risk execution

Blocks on the 2nd call of a detected chain. 0% FPR across 8.1M benign requests. Nobody else does this.

Guardrail 5: Rate Limiting

func (g *GuardrailMiddleware) OnRateLimitCheck(clientAddr string) error
Enter fullscreen mode Exit fullscreen mode

Per-client rate limiting with configurable RPM. Tracks in sliding window buckets. Developer tier: 500 RPM. Enterprise: configurable. Prevents abuse without breaking legitimate use.

Guardrail 6: MCP Response Guard

func (rs *MCPResponseScanner) ScanMCPMessage(ctx context.Context, message interface{}, sessionID string) (*responseguard.ResponseScanResult, error)
Enter fullscreen mode Exit fullscreen mode

Scans MCP tool responses for PII, secrets, and XSS before they reach the client. StrictMode = true by default — fail-closed. If a tool response contains an AWS API key, it doesn't reach the LLM. Per-session stats track PIIFound, SecretsFound, BlockedResponses.

This addresses CyberArk's "Poison everywhere" finding — tool outputs can contain prompt injection and sensitive data. We scan them before they hit the context window.

Guardrail 7: Audit Logging + SIEM Export

Every session, every tool call, every block, every alert is logged with timestamp, session ID, agent ID, detection results, and block/allow decision. SIEM-exportable format. If an agent does something at 2 AM on a Tuesday, you'll know exactly what it did.


The Spec Says MUST. We Enforce It.

Spec MUST AegisGate Guardrail Status
Servers MUST validate all tool inputs Guardrail 2 + Guardrail 3 (STDIO validation) ✅ Enforced
Servers MUST implement proper access controls Guardrail 2 (tool authorization + tier gating) ✅ Enforced
Servers MUST rate limit tool invocations Guardrail 5 (per-client rate limiting) ✅ Enforced
Servers MUST sanitize tool outputs Guardrail 6 (MCP Response Guard) ✅ Enforced

The spec says servers MUST do these things. We built the middleware that does them. Every MCP connection that goes through AegisGate gets all four — plus chain analysis, neural detection, and session management that the spec doesn't even mention.


What the Spec Doesn't Say (And We Built Anyway)

The spec's security section is advisory. It says what servers SHOULD do. It doesn't provide:

  • Chain analysis — the spec doesn't mention multi-turn attack detection at all. We built it because the OpenAI hack proved it's the most important detection layer.
  • Neural threat detection — the spec doesn't mention ML-based prompt injection detection. We trained a 1.6M parameter CharCNN-BiLSTM model because regex can't catch novel attacks.
  • STDIO command validation — the spec doesn't mention shell metacharacter injection in the STDIO transport. We built it because OX Security documented the attack vector.
  • Response guard with fail-closed mode — the spec says to sanitize outputs but doesn't define fail-closed behavior. We default to StrictMode = true because "fail open" is not a security posture.

How It Works in Practice

Start the platform with the embedded MCP server:

./aegisgate-platform --embedded-mcp
Enter fullscreen mode Exit fullscreen mode

Connect any MCP client. Every JSON-RPC request passes through the guardrail middleware:

Client → MCP JSON-RPC → GuardrailMiddleware → Tool Execution → Response Guard → Client
                              ↓
                    Session limit check
                    Tool authorization
                    STDIO validation
                    Chain analysis
                    Rate limiting
                              ↓
                    Block or Allow
Enter fullscreen mode Exit fullscreen mode

If a tool call triggers an EscalationChain at Turn 2:

{
  "jsonrpc": "2.0",
  "id": 4,
  "error": {
    "code": -32000,
    "message": "P2-EscalationChain detected: multi-turn attack pattern blocked",
    "data": {
      "guardrail": "chain_analysis",
      "chain_type": "escalation",
      "session_id": "sess-abc123",
      "turn": 2
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The client gets a structured JSON-RPC error. The SIEM gets an alert. The audit log captures everything. The attacker never gets to Turn 3.


The E2E Test Coverage

We didn't just build the guardrails — we wrote end-to-end tests that start the actual platform binary, connect via raw TCP MCP JSON-RPC, and exercise each guardrail:

//go:build e2e

func TestGuardrailIntegration_Initialize(t *testing.T)      // Server starts, guardrails active
func TestGuardrailIntegration_ToolAuth_ShellCommandBlocked  // Guard 2b: shell_command blocked
func TestGuardrailIntegration_StdioValidation(t *testing.T) // Guard 6: shell metacharacters blocked
func TestGuardrailIntegration_RateLimit(t *testing.T)       // Guard 5: per-client rate limiting
func TestGuardrailIntegration_SessionLimit(t *testing.T)    // Guard 1: concurrent session limit
func TestGuardrailIntegration_ResponseGuard_PII(t *testing.T)    // PII in response blocked
func TestGuardrailIntegration_ResponseGuard_CleanResponse(t *testing.T) // Clean response passes
Enter fullscreen mode Exit fullscreen mode

Every guardrail has an E2E test that connects to the real server and verifies the block at the protocol level. Not unit tests with mocks — real TCP connections, real JSON-RPC, real enforcement.


The Honest Assessment

I'm not going to claim we've "solved" MCP security. Here's what we haven't done:

We don't have production MCP traffic yet. All validation is synthetic. The 8.5M request stress test used generated payloads, not real MCP sessions from real users. That's the design partner conversation.

P4 and DIST2-5 are alert-only. Anomaly detection and distillation detection are validated for false positives (0% across 8.1M benign requests) but not true positives. They need real traffic variation. We won't flip them to blocking until we have that data.

We haven't been third-party pentested yet. The guardrails are tested via E2E integration tests, but we haven't had an external security firm try to break them. That's SBIR-gated ($15-30K).

The MCP spec is still evolving. The 2026-07-28 stable release is the first "stable" version. The authorization spec was rewritten mid-year. Things will change. We'll adapt.

But here's what I will claim: we built more MCP runtime security than anyone else has. The spec says MUST. We enforce it. The research community documented 9+ vulnerabilities in 9 months. We built defenses for every single one of them. And we added chain analysis — the one detection layer that nobody else has — because multi-turn attacks are the real threat.


References


Josh Colvin is the solo founder of AegisGate Security, building open-source, self-hosted AI security. Apache 2.0. No telemetry. No data egress. GitHub.

Top comments (0)