SuperAPI AI Directory

mcp-server-security

Agents & models

View repository

Updated 10-16 03:14

About this skill

mcp-server-security

MCP security is not ordinary API security: the caller is a manipulable LLM, the server's own metadata is executable-ish content in someone else's context, and agents retry, parallelize, and obey instructions found in data. This skill encodes the attack classes documented in real disclosures and the defenses that counter them. Auth mechanics (OAuth, audiences, tokens) live in mcp-server-auth; this skill assumes identity exists and hardens everything else.

When NOT to use

  • Implementing OAuth/discovery/token validation → mcp-server-auth.
  • Building the server / transport wiring → mcp-server-implementation (the Origin/localhost/session-ID floors are set there; this skill explains the attacks behind them).
  • Generic web/infra scanning, container CVEs, non-MCP pentesting.

Workflow

1. Threat-model against the MCP taxonomy

Walk references/threats.md (each attack: mechanism, real incident, defenses). Summary table:

Attack One-line mechanism Canonical defense
Tool poisoning hostile instructions in descriptions/schema fields the user never sees pin + hash descriptions; scan in CI; client-side re-approval
Rug pull benign tool swapped post-approval via list_changed version-pin servers; alert on description drift
Injection via tool results fetched/user content carries instructions the model obeys delimit + sanitize all external content; treat output as untrusted input
Confused deputy server's own credential exercised on behalf of the wrong caller per-client consent; audience validation (see mcp-server-auth)
Session hijacking guessable/replayed session IDs crypto-random IDs bound to user identity; sessions never = auth
SSRF tool or discovery fetches attacker-chosen URLs scheme/host allowlists; block private + metadata ranges pre-fetch
Command injection tool args reaching a shell / stdio params executed no shell-out with user input; safe APIs; treat local servers as code execution
Supply chain malicious/compromised server package pin versions; review; sandbox; registries don't vet for you
Denial of wallet unbounded expensive calls (OWASP LLM10) per-identity quotas, cost caps, retry-after

2. Guardrails in code, not prompts

Test: if the system prompt were deleted, would the constraint still hold? Amount caps, tenancy checks, jurisdiction rules, "never delete without confirmation" — all if + refuse in the handler, never instructions in a description. Make reads easy, writes expensive:

  • Destructive tools: explicit confirmation gate (elicitation where supported, or a two-step confirm token), honest destructiveHint, separate write scope.
  • Idempotency keys on every mutating tool — agents retry by design; store (caller, key) with a TTL, return the original result on replay.
  • Validate inputs at two layers: schema at the protocol boundary, business rules in the handler (path traversal: resolve + verify inside root; never interpolate into SQL/shell).

3. Contain the blast radius

  • Run servers sandboxed: container/micro-VM, non-root, read-only FS where possible, minimal egress allowlist. Treat third-party local servers as arbitrary code execution on the host — because stdio servers are exactly that (the SDKs' param-to-shell behavior is documented as by-design).
  • Secrets: environment/secret manager only; never in code, client-config args, or logs. Short-lived credentials where the backend allows.
  • Per-tool rate limits AND per-identity cost quotas; a kill switch per tool (feature flag/Redis set) that disables it without a redeploy.
  • Egress DLP for tools returning records: redact PII/credentials fields the caller's scope doesn't justify.

4. Audit everything, tamper-evidently

One audit event per tool call: caller identity, tool, sanitized args (or a safe summary), outcome, latency, session — to a separate append-only store (SIEM), not the app database. A web-access log is not an audit trail; compliance regimes (SOC 2, HIPAA, PCI) expect attributable, tamper-evident records. Never log tokens or raw secrets. Alert on: guardrail-block spikes, description drift, per-caller cost anomalies, session-length outliers.

5. Sanitize the model-facing surface

  • Wrap external/tool-fetched content in explicit delimiters (<external_data source="...">) and screen for injection phrases before returning — code-level, applied unconditionally; neither delimiting nor screening is sufficient alone.
  • Never echo unfiltered third-party content into errors or descriptions.
  • Annotations are UX hints; clients must not trust them from untrusted servers — never rely on your own annotations as an access control.

6. Gate it in CI

python3 "${CLAUDE_SKILL_DIR}/scripts/security_checklist.py" --repo .

prints the deterministic checklist (pinning, secrets, drift detection, guardrail evals) with PASS/FAIL per item where detectable, TODO where judgment is needed; non-zero exit on failures. Add description-drift scanning (e.g. mcp-scan-class tooling) and a guardrail regression eval (a prohibited action must be refused) to the pipeline — methodology in mcp-server-testing.

Output spec

A hardened server: taxonomy reviewed with written dispositions; destructive tools confirmed + idempotent; two-layer validation; sandboxed runtime with minimal egress; per-tool limits + kill switches; separate audit store wired; external content delimited/sanitized; CI running the checklist + drift detection; secrets and logs clean.

Gotchas

  • Stronger models are MORE injectable via tool results, not less — better instruction-following widens this attack. Never reason "the model will ignore it".
  • Vet third-party servers like dependencies with hands: review, pin the version, hash the tool descriptions, sandbox. Registries (official one included) do not security-review listings.
  • Several defenses are the client's job (consent UI, re-approval on change, sandboxing the server process) — a perfect server still needs a competent host; say so in your security docs.
  • Institutional baselines exist — NSA's MCP CSI, OWASP GenAI's secure-MCP guide, CSA's agentic-security practices — cite them to auditors instead of arguing from blogs (index in references/threats.md).
  • Real incidents to learn from, not repeat: postmark-mcp (npm server silently BCC'ing mail), CVE-2025-6514 (mcp-remote RCE), CVE-2025-49596 (old Inspector), SSRF-via-discovery in both major SDKs.

Pointers

  • references/threats.md — full taxonomy with mechanisms, disclosed incidents/CVEs, defenses, and the institutional-guidance index.
  • scripts/security_checklist.py — deterministic CI checklist runner.