← Attack Database

Compromised MCP server package

Supply chain verified

Compromised MCP server package

Summary

A compromised MCP package is a legitimate or legitimate-looking MCP server distributed via a package registry (npm, PyPI) whose code is modified — either by the original maintainer after account takeover, or by a typosquatted/impersonating publisher — to include behaviour that exfiltrates data, injects secondary payloads, or manipulates tool output. Because most MCP clients run JavaScript/TypeScript servers directly with npx and Python servers with uvx/pipx, the server inherits the full privileges of the host: filesystem, environment variables, network access. A single malicious version can reach every agent that pulls @latest on the next install.

How it works

  1. Attacker gains a publish vector, typically one of:
    • Impersonation: publish an npm package with the name of a known MCP server the registry does not own (postmark-mcp, stripe-mcp, etc.).
    • Maintainer account takeover via phishing (the September 2025 chalk/debug campaign used a fake npmjs.help 2FA page).
    • Worm-style propagation: malware running on an infected maintainer’s machine scans ~/.npmrc / environment for publish tokens and republishes every package the maintainer controls (Shai-Hulud, Shai-Hulud 2.0).
  2. The package ships identical behaviour to the legitimate server for N releases to build trust and accumulate installs.
  3. A subsequent version injects the payload. Common patterns observed:
    • A one-line modification to an exposed tool (BCC every outgoing email, swap a destination address, log arguments to an attacker endpoint).
    • A preinstall/postinstall script that runs on npm install, before any MCP handshake, harvesting secrets with TruffleHog-style scanners.
    • Obfuscated secondary payloads (setup_bun.js, bun_environment.js in Shai-Hulud 2.0) that persist and spread to other packages using stolen tokens.
  4. The MCP client (Claude Desktop, Cursor, Windsurf, custom agents) resolves @latest on next startup, executes the compromised code with the user’s credentials, and the agent begins calling tools whose implementation now leaks data or tampers with results.

Real-world example

postmark-mcp (September 2025) — first confirmed malicious MCP server in the wild

  • Package: postmark-mcp on npm, published by user phanpak (who owned 31 other packages).
  • Technique: Impersonation. The attacker cloned the legitimate ActiveCampaign/Postmark MCP server source, republished under the same short name, and maintained behaviourally identical releases for versions 1.0.0 through 1.0.15.
  • Payload: Version 1.0.16, published 17 September 2025, added a single line to the send_email tool that silently BCC’d every outgoing email to phan@giftshop.club.
  • Reach: ~1,500 weekly downloads at time of disclosure; ~1,643 total downloads cited by multiple trackers. Used by developers wiring Postmark into AI/automation pipelines, which routinely handle password resets, invoices, customer communications, and internal memos.
  • Disclosure: Koi Security (26 September 2025), covered by Snyk, The Hacker News, Qualys, CSO Online. The package was removed from npm after disclosure. Postmark (ActiveCampaign) published a security advisory confirming the malicious package was not theirs.

Shai-Hulud / chalk-debug (September 2025) — indirect compromise of the MCP TypeScript SDK dependency tree

  • Initial vector: Maintainer Josh Junon (qix) was phished via a fake npmjs.help 2FA page on 8 September 2025. His npm account was used to publish malicious versions of 18 packages — chalk, debug, ansi-styles, strip-ansi, supports-color, and others — with combined weekly downloads of ~2.6 billion.
  • MCP impact: Several of the compromised packages are transitive dependencies of the official @modelcontextprotocol/sdk. Any TypeScript MCP server built on the SDK and installed during the compromise window was potentially running the malicious payload. The initial payload targeted cryptocurrency wallet activity (swapping transaction destinations in browser contexts).
  • Worm: Within 24 hours, the Shai-Hulud worm emerged — malware that harvests npm/GitHub/AWS/GCP tokens from an infected machine, republishes the maintainer’s packages with itself embedded as a postinstall, and spreads. Socket identified close to 500 impacted npm packages by 16 September. A second wave (Shai-Hulud 2.0, late November 2025) compromised ~796 additional packages using setup_bun.js / bun_environment.js and a preinstall trigger.
  • Sources: CISA alert (23 September 2025), Unit 42, Datadog Security Labs, JFrog, AWS security blog, Red Hat advisory.

mcp-remote (CVE-2025-6514) — adjacent supply-chain risk

Not a compromised package itself, but a widely installed MCP client library (437,000+ downloads) vulnerable to OS command injection when connecting to an untrusted MCP server via a malicious OAuth authorization_endpoint. Disclosed by JFrog in July 2025, CVSS 9.6. Fixed in 0.1.16. Illustrates that even the client side of the supply chain is exploitable.

Impact

  • Credential theft. Environment variables, ~/.aws/, ~/.ssh/, .env files, npm/GitHub/cloud tokens. Shai-Hulud specifically uses TruffleHog to sweep secrets.
  • Data exfiltration from tool calls. Anything routed through the tool (emails in postmark-mcp, DB queries in a postgres-mcp, git operations in a github-mcp).
  • Agent manipulation. Tool outputs can be silently altered before reaching the LLM, steering downstream decisions (wrong wallet address, modified file contents, fabricated search results).
  • Lateral propagation. Worm-style packages republish the victim maintainer’s other packages, so one compromise can poison an entire dependency subtree.
  • Persistence. postinstall/preinstall scripts execute before any MCP handshake, so runtime policy enforcement at the MCP transport layer cannot intercept installation-time payloads.

Detection

  • Pin exact versions in client configs; never use @latest for MCP servers. Alert on any resolved version change in CI or on startup.
  • Diff newly resolved node_modules / Python site-packages against the previous lockfile.
  • Monitor MCP server process egress. A legitimate Postmark server should talk to api.postmarkapp.com only — not giftshop.club or similar.
  • Watch for BCC headers, unexpected recipients, or modified tool arguments in logs of any tool that sends external messages.
  • Hash or signature-check tool definitions on startup and compare to a known-good manifest (see Prevention).
  • Subscribe to Socket, Snyk, npm security advisories for the specific packages you install.
  • Run MCP servers in a sandbox (Docker, firejail, bubblewrap) so postinstall payloads cannot reach host secrets.

Prevention

Transport-layer policy enforcement cannot stop a malicious postinstall that runs before the proxy starts, so the first line of defence is install-time (lockfiles, sandboxing, allowlisted registries). Once the server is running, however, Intercept reduces blast radius in two ways:

  1. Allowlist tools. Set default: deny and explicitly list only the tools your agent is supposed to use. If the compromised server adds a new tool (e.g. send_diagnostic_report) in a later release, the agent cannot call it — the call is rejected before reaching the upstream.
  2. Hide destructive tools. Tools the agent never legitimately needs (delete_*, transfer_*, raw shell execution) can be stripped from tools/list so the model never sees them and prompt-injection-driven misuse is eliminated.

Example — locking down a Postmark MCP server to only the single tool the agent legitimately needs:

version: "1"
description: "Postmark MCP — allowlist to contain a compromised upstream"
default: deny

tools:
  send_email:
    rules:
      - name: "hourly send limit"
        rate_limit: 20/hour
        on_deny: "Hourly email limit reached"

      - name: "approved recipients only"
        conditions:
          - path: "args.to"
            op: "regex"
            value: "^[^@]+@(yourcompany\\.com|yourcustomer\\.com)$"
        on_deny: "Recipient not on approved list"

Under default: deny, any new tool the compromised package adds (send_diagnostic, register_webhook, get_api_key) is auto-rejected without needing a policy update.

Drift detection (roadmap, speculative): a future Intercept feature would hash the tools/list response on first connection and alert or block when it changes. The current release enforces an explicit allowlist instead, which achieves the same outcome for new tools but does not detect silent semantic changes to an existing tool’s behaviour. See the MCP rug pull page for that attack pattern specifically.

Sources

Protect your agent in 30 seconds

Scans your MCP config and generates enforcement policies for every server.

npx -y @policylayer/intercept init
github.com/policylayer/intercept →
// GET IN TOUCH

Have a question or want to learn more? Send us a message.

Message sent.

We'll get back to you soon.