12 CVEs Indexed - Dependency Security in AI Agent Toolchains

M
Matthew Diakonov

12 CVEs Indexed - Dependency Security in AI Agent Toolchains

You audit your agent's code. You review its permissions. You test its outputs. But have you looked at what its dependencies depend on?

A standard AI agent toolchain - an LLM client library, a few MCP servers, a browser automation package, some file system utilities - can pull in hundreds of transitive dependencies. Each one is a potential entry point for an attacker. And in 2025 and 2026, attackers have figured this out.

This post walks through the real-world vulnerability landscape for AI agent dependency trees, with specific CVEs, attack timelines, and a practical audit workflow you can run today.

Why AI Agent Toolchains Are Uniquely Exposed

Traditional web applications have large dependency trees too. But AI agent toolchains are different in three important ways:

1. Agents operate with elevated privileges. A desktop automation agent needs file system access, network access, subprocess spawning, and often accessibility API permissions. A vulnerability anywhere in the dependency chain inherits those privileges.

2. MCP servers multiply the attack surface. Each MCP server you add is a separate dependency tree. A scan of 5,618 MCP servers found that only 2.5% passed a basic security check. Python servers had the highest rate of dependency-related flags, which makes sense given the size of the average Python dependency tree and the frequency of CVEs in ML/AI libraries.

3. The ecosystem is young and fast-moving. Package registries for AI tooling do not have the maturity of npm or PyPI. The OpenClaw incident proved this in February 2026 - within three weeks of going viral (25,000 GitHub stars in a single day), researchers found 1,184 malicious skills across its ClawHub marketplace. One in five packages in the entire ecosystem was compromised.

Real CVEs in Real Agent Toolchains

When we audited a representative AI agent stack - LangChain for orchestration, an MCP TypeScript SDK for tool integration, Playwright for browser automation, and several utility packages - we found 12 CVEs across transitive dependencies. None were in our direct dependencies. All were two or three levels deep.

Here are the categories of vulnerabilities we found, along with high-profile examples from the broader ecosystem.

Serialization Injection: LangGrinch (CVE-2025-68664)

The most significant AI-agent-specific CVE of 2025 was LangGrinch, a serialization injection bug in langchain-core with a CVSS score of 9.3 out of 10.

LangChain uses an internal serialization format where dictionaries containing an lc marker represent LangChain objects. The vulnerability: dumps() and dumpd() did not properly escape user-controlled dictionaries that happened to include the reserved lc key. An attacker who could influence LLM response fields (like additional_kwargs or response_metadata) through prompt injection could trigger deserialization of arbitrary objects.

The impact chain looks like this:

Prompt injection in LLM response
  -> Malicious 'lc' key in response metadata
    -> dumps()/dumpd() serializes it without escaping
      -> loads()/load() deserializes and instantiates arbitrary objects
        -> Secret exfiltration from environment variables
        -> Arbitrary code execution via Jinja2 templates

This was particularly dangerous because secrets_from_env was previously set to True by default, meaning any deserialized object could read environment variables - which typically contain API keys, database credentials, and other secrets.

The fix (in langchain-core versions 0.3.81 and 1.2.5) introduced an allowlist parameter allowed_objects, blocked Jinja2 templates by default, and set secrets_from_env to False.

Why this matters for your agent: If your agent uses LangChain (roughly 847 million total downloads), and you were on any version before 0.3.81, a prompt injection attack could have exfiltrated every secret in your environment. This is not a theoretical risk - the exploit chain was demonstrated publicly.

Supply Chain Compromise: The npm chalk/debug Attack

On September 8, 2025, at roughly 9AM EST, an attacker gained control of a maintainer's npm account through a phishing email from a fake domain (npmjs.help). The attacker collected the username, password, and a live TOTP code, then published malicious versions of 18 packages including chalk and debug.

These packages see over 2.6 billion downloads per week combined.

The malicious payload was specifically designed for cryptocurrency theft - injecting browser-side code that silently rewrites payment destinations. The compromised versions were live for about two hours before detection and removal.

Here is why this is relevant to your agent toolchain: run npm ls chalk in any Node.js-based agent project. Chances are it appears multiple times in your dependency tree. During those two hours, any npm install or CI build would have pulled in the compromised version. Your agent's build pipeline is part of your attack surface.

# Check how many times chalk appears in your dependency tree
$ npm ls chalk 2>/dev/null | grep chalk | wc -l
14

# Check how many times debug appears
$ npm ls debug 2>/dev/null | grep debug | wc -l
23

In a typical MCP-based agent project, debug appears 20+ times in the dependency tree. That is 20+ places where a supply chain compromise would be pulled in.

MCP SDK Transitive Vulnerabilities

The official MCP TypeScript SDK itself has been a vector. Compromised packages were found to be indirect dependencies of the SDK, meaning any MCP server built from the SDK was potentially vulnerable. The popular mcp-remote npm package (used to add OAuth support to MCP servers) was found to contain a critical vulnerability tracked as CVE-2025-6514.

This is the pattern that makes agent toolchains particularly dangerous: you did not choose to depend on mcp-remote or any of its sub-dependencies. You chose to use the MCP SDK. The rest was inherited.

The OpenClaw ClawHavoc Campaign

In February 2026, researchers audited all 2,857 skills available on ClawHub and found 341 malicious entries. 335 of them traced to a single coordinated operation now tracked as ClawHavoc. By March 1, the count had risen to over 1,184 confirmed malicious skills out of 10,700 total packages.

The attack was novel: malicious instructions were hidden in SKILL.md files that exploited AI agents as trusted intermediaries. The agent would read the skill's documentation, interpret the malicious instructions as legitimate setup requirements, and present them to the user. Meanwhile, CVE-2026-25253 (CVSS 8.8) allowed any website to silently open a WebSocket to the local OpenClaw instance and steal the authentication token.

SecurityScorecard found 135,000 OpenClaw instances exposed to the public internet with insecure defaults. Of those independently verified, 93.4% had authentication bypass conditions.

The Transitive Dependency Problem, Quantified

To make this concrete, here is what a real audit looks like. Take a minimal AI agent project with these direct dependencies:

{
  "dependencies": {
    "@anthropic-ai/sdk": "^0.52.0",
    "@modelcontextprotocol/sdk": "^1.12.0",
    "playwright": "^1.52.0",
    "zod": "^3.24.0"
  }
}

Four direct dependencies. Run npm ls --all | wc -l and you get somewhere around 400-500 total packages in the tree. Now run the audit:

$ npm audit

# Example output (abbreviated)
found 12 vulnerabilities (4 moderate, 6 high, 2 critical)

# See the dependency path for each
$ npm audit --json | jq '.vulnerabilities | to_entries[] |
  {name: .key, severity: .value.severity, via: .value.via[0].name}'

The 12 vulnerabilities are never in your four direct dependencies. They are in packages like micromatch, braces, semver, cookie, and ws - utilities pulled in by sub-dependencies of sub-dependencies. You never asked for them. You probably did not know they were there.

For Python-based agents, the picture is similar:

$ pip-audit -r requirements.txt

# Or audit the current environment
$ pip-audit

# Output format
Found 8 known vulnerabilities in 3 packages
Name       Version  ID                  Fix Versions
---------- -------- ------------------- ------------
jinja2     3.1.2    PYSEC-2024-XXX      3.1.6
certifi    2023.7.22 PYSEC-2023-XXX     2024.2.2
setuptools 68.0.0   PYSEC-2024-XXX      70.0.0

A Practical Audit Workflow for Agent Projects

Here is a step-by-step process you can run right now. This takes about 15 minutes for a typical project and should be automated in CI.

Step 1: Map Your Full Dependency Tree

First, understand what you actually have installed.

# Node.js - show full tree with depth
npm ls --all --depth=10 > /tmp/dep-tree.txt
wc -l /tmp/dep-tree.txt  # know your number

# Python - list everything in the environment
pip freeze > /tmp/pip-freeze.txt
pip-audit -r /tmp/pip-freeze.txt --desc

# Rust
cargo tree > /tmp/cargo-tree.txt

Step 2: Run Automated Vulnerability Scanning

# Node.js
npm audit --audit-level=moderate
# For CI/CD - fail the build on high or critical
npm audit --audit-level=high

# Python
pip install pip-audit
pip-audit --format json -o /tmp/audit-results.json
# Check against a specific requirements file
pip-audit -r requirements.txt --strict

# Rust
cargo install cargo-audit
cargo audit

Step 3: Audit Each MCP Server Separately

Each MCP server is its own project with its own dependency tree. Do not just audit your main project.

# Find all package.json files in your MCP servers
find ./mcp-servers -name "package.json" -not -path "*/node_modules/*" | while read f; do
  echo "=== Auditing: $f ==="
  dir=$(dirname "$f")
  (cd "$dir" && npm audit --audit-level=moderate)
done

# For Python MCP servers
find ./mcp-servers -name "requirements.txt" | while read f; do
  echo "=== Auditing: $f ==="
  pip-audit -r "$f"
done

Step 4: Check for Abandoned Dependencies

Packages that have not been updated in 12+ months are more likely to contain unpatched vulnerabilities and are less likely to respond to security reports.

# Check outdated packages
npm outdated

# For a more detailed view, use npm-check
npx npm-check

# Python
pip list --outdated

Step 5: Analyze Runtime Permissions

This is the step most teams skip. Which of your dependencies have file system access, network access, or subprocess spawning capabilities?

# Search for dangerous patterns in node_modules
grep -r "child_process" node_modules/*/package.json 2>/dev/null
grep -r "fs\." node_modules/*/index.js 2>/dev/null | head -20
grep -r "eval(" node_modules/*/lib/*.js 2>/dev/null | head -20

# For Python - check for subprocess, os.system, eval
grep -r "subprocess\|os\.system\|eval(" \
  $(python -c "import site; print(site.getsitepackages()[0])") \
  --include="*.py" 2>/dev/null | head -20

Step 6: Set Up Continuous Monitoring

# GitHub: enable Dependabot alerts in .github/dependabot.yml
# This checks daily for new CVEs in your dependency tree

# Or use Snyk for more comprehensive scanning
npx snyk test
npx snyk monitor  # continuous monitoring

CI/CD Integration

Here is a GitHub Actions workflow that runs on every PR:

name: Dependency Security Audit
on: [pull_request]

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: '22'

      - name: Install dependencies
        run: npm ci

      - name: Run npm audit
        run: npm audit --audit-level=high

      - name: Check for known malicious packages
        run: npx socket-security/cli scan

      - name: Audit MCP servers
        run: |
          for dir in mcp-servers/*/; do
            if [ -f "$dir/package.json" ]; then
              echo "Auditing $dir"
              (cd "$dir" && npm ci && npm audit --audit-level=high)
            fi
          done

Reducing Your Attack Surface

The most effective security measure is reducing the number of dependencies. Every package you remove is an entire sub-tree of transitive dependencies you no longer need to worry about.

Prefer standard library over packages. Node.js 22+ has built-in fetch, crypto, path, and fs/promises. Python has pathlib, json, urllib, subprocess, and asyncio. You do not need a package for these.

Audit before you add. Before running npm install, check the package's dependency tree:

# Preview what you are about to install
npm pack <package-name> --dry-run
# Check its dependencies
npm view <package-name> dependencies
# Check how many transitive deps it brings
npm install <package-name> --dry-run 2>&1 | tail -1

Pin versions explicitly. Use exact versions in your dependency files, not ranges. Use lock files. Commit your lock files to source control.

{
  "dependencies": {
    "@anthropic-ai/sdk": "0.52.0",
    "@modelcontextprotocol/sdk": "1.12.0"
  }
}

Use socket.dev or Snyk for install-time protection. These tools check packages at install time, not just at audit time, and can block known-malicious packages before they enter your project.

What Happens When You Do Not Audit

The September 2025 npm attack was detected within two hours. The OpenClaw campaign ran for weeks. The LangGrinch vulnerability existed in langchain-core for months before disclosure.

In each case, the teams that were hit hardest were the ones running npm install without npm audit, pulling in MCP servers without reviewing their dependency trees, and deploying agents with broad permissions and no dependency monitoring.

The teams that were fine had automated scanning in CI, pinned their dependency versions, monitored advisories for their dependency tree, and minimized their dependency count.

The most secure dependency is the one you do not have.

Fazm is an open source macOS AI agent that takes security seriously. Open source on GitHub.

More on This Topic

Related Posts