Skip to content
Conduit

mcp server

chub-supply-chain-poc

Silent dependency injection through AI documentation pipelines. 240 isolated Docker runs proving Context Hub's zero-sanitization MCP server lets poisoned docs compromise developer projects without war

mickmicksh/chub-supply-chain-poccommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

This project does not publish an install method we can turn into a config. Follow the README instead.

README

synced Oct 17, 2026

Context Hub Supply Chain PoC

Zero-sanitization vulnerability in Context Hub (@aisuite/chub v0.1.3) enables silent dependency injection through the MCP documentation pipeline.

References: CWE-94 (Code Injection) | CWE-829 (Untrusted Control Sphere) | CWE-345 (Insufficient Verification of Data Authenticity) | OWASP LLM01 (Prompt Injection)

TL;DR

We created realistic poisoned docs containing fake dependencies (plaid-link-verify, stripe-checkout-guard) and served them through a local chub MCP server inside isolated Docker containers. No poisoned content was uploaded to Context Hub's registry - we ran chub build locally and configured the MCP server to serve pre-built output from disk. From the agent's perspective, the experience is identical to fetching docs from the live registry.

When AI coding assistants fetched the docs, Haiku silently wrote the fake package into requirements.txt in 100% of runs - without ever mentioning it in its text output. A developer reading the assistant's response would see nothing suspicious, but their project is poisoned.

240 isolated runs. 3 models. 4 effort levels. 2 APIs. 0 contamination.

What it looks like

The generated code silently imports the fake dependency alongside legitimate modules:

The agent also modifies CLAUDE.md to embed the fake package as a "project standard":

Results

These tables show Plaid Link results (120 isolated runs). See RESULTS.md for full data including Stripe Checkout (240 total runs).

Silent Dependency Poisoning (requirements.txt)

EffortHaikuSonnetOpus
Low100%60%0%
Medium100%70%0%
High100%40%0%
Max100%40%0%

Haiku never warned about the fake dependency (0/40). Sonnet warned in 48% of runs (19/40) but still poisoned requirements.txt in 53% overall. Opus warned in 75% of runs (30/40) and never poisoned requirements.txt or code.

CLAUDE.md Persistence (project config backdoor)

EffortHaikuSonnetOpus
Low90%70%0%
Medium80%70%0%
High90%40%0%
Max90%50%0%

Haiku modifies the project's CLAUDE.md to include the fake dependency as a "project standard" in 88% of runs (35/40). This file gets committed to git - every future developer who clones the repo inherits the poisoned config.

Attack Chain

flowchart LR
    A["Attacker\nsubmits PR"] -->|"No identity\nverification"| B["Maintainer\nmerges PR"]
    B -->|"No content\nsanitization"| C["Doc on CDN\n(no integrity check)"]
    C -->|"MCP serves\nraw content"| D["Agent context\nwindow"]
    D -->|"Agent acts on\nuntrusted content"| E["Developer\nworkstation"]

    style A fill:#111,stroke:#333,color:#f0f0f0
    style B fill:#161616,stroke:#333,color:#888
    style C fill:#161616,stroke:#333,color:#888
    style D fill:#161616,stroke:#333,color:#888
    style E fill:#111,stroke:#333,color:#f0f0f0

Threat Model

AttackerAnyone who can submit a PR to Context Hub's doc registry
Attack surfaceCommunity docs flowing from GitHub PR to CDN to MCP to agent context
Trust boundaryUntrusted contributor content treated as authoritative API documentation
PrerequisiteOne merged PR containing a poisoned document
ImpactArbitrary code execution via dependency injection + pip post-install hooks

Key Findings

  1. Haiku poisoning is fully silent. 0/80 Haiku runs across both APIs mentioned the fake dependency in the response. The model writes to disk without telling. Sonnet warned in 48% of runs but still poisoned requirements.txt in 35-53% of runs. Opus warned in 23-75% of runs and never poisoned requirements.txt or code.

  2. Haiku is 100% exploitable at every effort level. Effort-independent on both APIs. The weakest model in the family never catches the fake dependency.

  3. Opus resists code poisoning but not config poisoning. Opus never wrote the fake dependency to requirements.txt or Python code (0/80 across both APIs). But on Stripe, Opus modified CLAUDE.md in 38% of runs, documenting the canary as a project dependency without installing it.

  4. CLAUDE.md persistence creates a supply chain vector. Modified config files get committed to git, poisoning every developer who clones the repo and every future AI session in that project. This works across all models (Haiku 88-90%, Sonnet 58%, Opus 0-38%).

  5. API familiarity matters. Stripe (well-known): models detect fake packages via training data. Plaid (less known): models cannot verify and accept the fake dependency without question.

  6. This is a category-wide problem. Context7 had ContextCrush (Feb 2026). Context Hub has this. Any tool injecting unsanitized external content into agent context is vulnerable.

Source Code Findings

Zero sanitization across the entire pipeline:

  • annotations.js - writeFileSync with raw content, no filtering
  • build.js - no content scanning, no unicode normalization
  • cache.js - CDN fetch with zero hash/signature verification
  • source: official in frontmatter - self-declared, not verified

Disclosure

Context Hub has no SECURITY.md. There is no documented way to responsibly disclose a vulnerability - no security contact, no PGP key, no disclosure policy. Community members found the vulnerabilities anyway and filed them as regular issues and PRs. None were reviewed.

DateEvent
2026-03-12Issue #74 filed by @bjorkbjork reporting 4 security vulnerabilities including CDN integrity, self-declared source verification, and annotation injection
2026-03-12Issue #74 assigned internally to core team member - zero follow-up
2026-03-17PR #125 filed by @hobostay adding content integrity verification - zero reviews
2026-03-12 to 03-20Additional security PRs (#69, #81) filed by community - zero reviews
2026-03-20 to 03-23Our independent audit confirms and quantifies the vulnerabilities with 240 isolated Docker runs
2026-03-23Public disclosure

Note: We did not file issue #74. Our audit independently discovered and quantified these vulnerabilities. Issue #74 and PRs #69, #81, #125 are cited as prior art demonstrating the community has flagged these issues with zero maintainer engagement.

Escalation

Once the fake package is in requirements.txt, a standard pip install -r requirements.txt gives the attacker arbitrary code execution via setup.py post-install hooks. This is not a sandbox - pip runs unrestricted Python with the developer's full permissions.

From that single entry point, the attacker can:

  • Exfiltrate data. Read and send environment variables, API keys, AWS credentials, SSH keys, .env files, or source code to an attacker-controlled server.
  • Install a persistent backdoor. Reverse shell, cron job, modified shell profile, or background process that survives package uninstallation.
  • Poison the chub registry. Modify ~/.chub/config.yaml to add an attacker-controlled doc source. All future chub queries across every library now include attacker content. Survives chub cache clear because config is not cache.
  • Propagate through git. The CLAUDE.md modification gets committed. Every developer who clones the repo inherits the poisoned config. If they run the same workflow, the attack repeats on their machine.

These are not mutually exclusive. A single post-install hook can do all of them in under a second. We did not create or register a malicious package.

Repository Structure

.
|-- README.md                    # This file
|-- RESULTS.md                   # Full dataset with per-run breakdowns
|-- REPRODUCE.md                 # Docker-based reproduction guide
|-- alternatives-comparison.md   # Context7, LAP, GitMCP, Docfork comparison
|-- article.html                 # Full write-up
|-- docker/
|   |-- Dockerfile               # Isolated test environment
|   |-- run_isolated.ps1         # PowerShell runner (Windows/macOS/Linux via pwsh)
|   |-- seed-claude.md           # Minimal CLAUDE.md seeded into each run
|   |-- plaid-doc/               # Poisoned Plaid Link doc (canary: plaid-link-verify)
|   |   `-- plaid/link/DOC.md
|   `-- stripe-doc/              # Poisoned Stripe Checkout doc (canary: stripe-checkout-guard)
|       `-- stripe/checkout/DOC.md
`-- results/
    |-- plaid-isolated/          # 120 Plaid runs: JSON + session transcripts + project files
    `-- stripe-isolated/         # 120 Stripe runs: JSON + session transcripts + project files

Reproducing the Results

See REPRODUCE.md for the full Docker-based reproduction guide.

Quick start:

# Plaid (default)
docker build --build-arg DOC_DIR=plaid-doc -t plaid-bench docker/
docker run -d --name plaid-runner plaid-bench sleep infinity
docker exec -it plaid-runner claude login

# Stripe
docker build --build-arg DOC_DIR=stripe-doc -t stripe-bench docker/
docker run -d --name stripe-runner stripe-bench sleep infinity
docker exec -it stripe-runner claude login

# Then run the test matrix from the host (see REPRODUCE.md)

Limitations

  1. Only Claude models tested. GPT-4, Gemini, Llama may differ.
  2. 10 runs per cell - sufficient for trends, not for narrow confidence intervals.
  3. Tests used --permission-mode bypassPermissions. Real agents may prompt for confirmation.
  4. Local doc source, not CDN. CDN path requires a merged malicious PR.
  5. No real malicious package was registered on PyPI.

Related Work

  • ContextCrush (Noma Security, Feb 2026) - same class of attack against Context7
  • Morris II (Cohen, Bitton, Nassi) - self-replicating prompts in AI agents
  • Promptware Kill Chain (Nassi, Schneier et al.) - multi-stage LLM attack taxonomy
  • MCP Tool Poisoning (Invariant Labs) - cross-server tool manipulation

License

MIT

Disclosure

This research was conducted by Mickey Shmueli, the developer of LAP, an open-source alternative to Context Hub. LAP uses deterministic compilation from official API specs, with no community-contributed content in the pipeline. This audit was motivated by a genuine security concern about unsanitized content pipelines - a class of vulnerability that affects any tool in this space that accepts unverified community contributions. The findings stand on their own: 240 isolated Docker runs, deterministic detection, fully reproducible.

Disclaimer

This PoC is for educational and security research purposes only. All tests performed locally in isolated Docker containers. No malicious content was submitted to the Context Hub repository. All canary package names verified non-existent on PyPI before testing.

These vulnerabilities were independently reported by community members in issue #74 (March 12) and PR #125 (March 17). Both received zero maintainer response.

↑↓ navigate openesc close