Skip to main content

RedCell

The MCP security scanner that actually exploits — it doesn't just lint your tool descriptions, it attacks your running server and proves what's broken.

Point RedCell at any MCP server and it enumerates the server's tools, then actively exploits them — proving path traversal, SSRF, OS command injection, tool-description poisoning, and secret leakage with a real exploit transcript, not a guess. One command, no adapter to write:

redcell scan -- python3 my_mcp_server.py
✗ CRITICAL  OS Command Injection · tool 'run_command' · OWASP MCP05
    An injected shell expression executed on the host: 4655*7529 resolved to 35047495.
    ↳ Payload: command='x; echo $((4655*7529))'
✗ CRITICAL  Path Traversal · tool 'read_file' · OWASP MCP03
    The tool returned /etc/passwd outside any intended directory (proven read).

Findings map to the OWASP MCP Top 10 and drop straight into CI (non-zero exit on findings, HTML + SARIF reports). Most MCP scanners statically lint tool descriptions; RedCell calls the tools and demonstrates the exploit — the high-signal, low-noise part everyone else skips.

⚠️ Defensive / authorized use only. Scan MCP servers and agents you own or have explicit permission to test. Payloads are deliberately non-destructive (read a world-readable file, hit a loopback listener, echo a canary). See RESPONSIBLE_USE.md.

Install

The core (and all stdio scanning) is stdlib-only — no dependencies.

uvx redcell scan -- python3 my_mcp_server.py        # run without installing (recommended)
pipx install redcell                               # or install the CLI globally
pip install redcell                                # or into your environment
# from source (before the PyPI release):  git clone … && pip install -e .

Scan an MCP server

# Try it on the bundled deliberately-vulnerable server (finds 6 classes → exit 1):
redcell scan -- python3 examples/mcp/vulnerable_server.py

# …and the hardened one (clean → exit 0):
redcell scan -- python3 examples/mcp/hardened_server.py

# Your own server, with reports for CI:
redcell scan --out report.html --sarif results.sarif -- python3 my_mcp_server.py
redcell scan --static-only -- python3 my_mcp_server.py   # inspect definitions, call nothing

What it checks (OWASP MCP Top 10), and how:

Check OWASP How it's proven
Path traversal / unsandboxed file read MCP03 calls file tools with ../../etc/passwd, confirms the leaked contents
Server-side request forgery MCP04 steers fetch tools at a loopback callback + file://, confirms the request fired
OS command injection MCP05 injects shell arithmetic $((a*b)); a finding fires only if the product comes back (reflection can't fool it)
Tool definition poisoning / line-jumping MCP01 scans tool descriptions/param schemas for hidden agent instructions
Tool output injection (ATPA) MCP02 calls tools benignly and inspects the output for injected instructions
Credential / secret leakage MCP06 flags keys/tokens/private-keys in definitions and outputs

The client speaks MCP over stdio (the common local case) with zero extra dependencies.

Scanning untrusted servers safely

Scanning a third-party server runs its code. To scan servers you don't trust, do it inside a throwaway, host-isolated container — no host filesystem is mounted, it's removed after each scan, and path-traversal/SSRF probes hit the container's /etc/passwd and loopback, never yours:

brew install colima docker && colima start      # one-time: a Linux VM for true isolation
sandbox/scan-sandboxed.sh -- npx -y some-untrusted-mcp-server

Also: full agent-loop red-teaming

Beyond MCP, RedCell red-teams the full agent loop — tools, retrieval, memory, and multi-step reasoning — where the under-covered vulnerabilities live (NIST found novel agent attacks hit an 81% task-hijack rate vs 11% for prompt-only attacks). It plays an adversary against a target agent and maps findings to the OWASP Top 10 for Agentic Applications (2026) and NIST AI 100-2.

Status

Early (v0.1, milestones M1–M2). What works today:

  • A pluggable engine: attacks → target → judge → report.
  • An attack library mapped to the OWASP Agentic Top 10, all via the indirect vector (payload delivered through a tool's output, not the user prompt):
    • Indirect prompt-injection → exfiltration (ASI01) — leak-in-output + egress-tool variants.
    • Privileged tool abuse (ASI03) — coaxing a destructive tool call.
    • Tool misuse / SSRF — fetch tool aimed at the cloud metadata endpoint.
  • A deterministic, criteria-driven HeuristicJudge (canary leak, forbidden-tool, unsafe tool argument) — no API key needed.
  • Deliberately vulnerable and hardened mock agents so you can verify the whole loop offline.
  • HTML + JSON reports with OWASP/NIST mapping, and a CI-friendly exit code.
  • Adaptive multi-turn red-teaming (redcell adaptive): a feedback-driven attacker that builds rapport then escalates — extracting a secret from a chat agent only after multiple turns (a weakness single-prompt scans miss). Runs offline with the scripted attacker; a real Claude-powered attacker + target are wired and gated behind ANTHROPIC_API_KEY (drop the key in, no code changes).

Adaptive multi-turn (offline)

redcell adaptive --target chat-vulnerable     # scripted attacker extracts the secret → exit 1
redcell adaptive --target chat-hardened       # resisted → exit 0

Real LLM attacker/target — bring any provider (free options included)

The LLM attacker and target are provider-agnostic (stdlib-only, no SDK lock-in). Pick a backend with --provider or an env key:

Provider Cost Setup
groq free key, no card export GROQ_API_KEY=...
ollama free, fully local, no key install Ollama, ollama pull llama3.1
openrouter free :free models export OPENROUTER_API_KEY=...
gemini free tier export GEMINI_API_KEY=...
anthropic paid export ANTHROPIC_API_KEY=... (pip install 'redcell[llm]')
# Free: a Groq-powered adversary vs. an Ollama-hosted target
redcell adaptive --attacker llm --provider groq --target llm-chat
# or fully local, no keys at all:
redcell adaptive --attacker llm --provider ollama --target llm-chat --provider ollama

Provider resolves from --providerREDCELL_LLM_PROVIDER → whichever API key is set. With nothing configured, RedCell prints the free-options menu instead of failing cryptically.

  • A labeled benchmark (redcell benchmark) over targets with known vulnerability profiles, reporting judge precision/recall/F1 and attack coverage per OWASP category — and honestly surfacing what the heuristic judge misses.

Roadmap (see the project plan): GitHub Action → an LLM-as-judge to close the recall gap the benchmark exposes → hosted cloud.

Benchmark + judges

redcell benchmark --md benchmark.md --json benchmark.json            # heuristic (offline)
redcell benchmark --judge hybrid --provider groq                     # + LLM backstop (free)

Three judges: heuristic (offline, exact, perfect precision), llm (semantic — catches obfuscated/encoded leaks; needs a provider), and hybrid (heuristic first, LLM only as a backstop on negatives — keeps precision, recovers recall, minimizes tokens).

Measured on the 20-case labeled benchmark:

Judge Precision Recall F1
heuristic 1.00 0.90 0.95
hybrid (+ LLM) 1.00 1.00 1.00

The heuristic's one miss is a deliberately space-obfuscated canary leak — a real vulnerability exact matching can't see. The LLM judge recovers it without introducing false positives.

Status & honest limitations

RedCell is an early, well-tested skeleton, not a battle-tested product. Findings are so far demonstrated against deliberately-vulnerable sample agents (no real-world findings yet), the attack library is smaller than mature tools, and the benchmark is synthetic. Read the candid build writeup for the full picture, results, and the roadmap that would matter for real adoption.

Quickstart (offline, no API key)

cd redcell
pip install -e .

# Run against the deliberately-vulnerable mock agent — should find the injection.
redcell run --target mock-vulnerable --out report.html

# Run against the hardened mock agent — should be clean.
redcell run --target mock-hardened --out report-hardened.html

Exit code is non-zero when vulnerabilities are found, so it drops straight into CI.

Test your own agent (HTTP) + CI

Point RedCell at any agent you own/are authorized to test by exposing an HTTP endpoint:

redcell run --target-url https://your-agent.example/redcell --out report.html

Your endpoint receives {user_input, injected_tool, injected_payload, canary} and returns {final_output, tool_calls:[...]} (full contract in http_adapter.py). Exit code is non-zero on findings.

Regression gating — record a baseline and fail CI only when a new vulnerability appears (pre-existing ones don't break the build):

redcell run --target-url $URL --history .redcell/history.jsonl --fail-on-new

Drop it into CI with the bundled GitHub Action — it fails the build on findings, emits SARIF to the Security tab, and uploads the report:

- uses: Sahilo6/redcell@v0
  with:
    target-url: https://your-agent.example/redcell

REST API (backend)

A FastAPI backend (the web frontend consumes it). Targets + scans are persisted in SQLite; scans run as background jobs you poll.

pip install -e ".[api]"
redcell serve            # http://127.0.0.1:8000 · interactive docs at /docs

MCP scanning over HTTP — the flagship scanner as a pollable job: POST /mcp/scans (body {command, static_only?, timeout?, name?}) → poll GET /mcp/scans/{id}GET /mcp/scans/{id}/report.html|.sarif; plus GET /mcp/probes, GET /mcp/stats (dashboard aggregates), and DELETE /mcp/scans/{id}.

⚠️ POST /mcp/scans launches the given command on the host — running it executes the MCP server's code. Today it runs locally (set REDCELL_API_KEY and don't expose it on an untrusted network). For a hosted/multi-user deployment, route scans through the sandbox harness — the seam is service.execute_mcp_scan.

Agent red-teaming endpoints (pre-MCP, still supported): POST /targets, POST /scans (→ poll GET /scans/{id}), GET /scans/{id}/report.html|.sarif, GET /stats, GET /benchmark, POST /adaptive, GET /attacks, GET /health.

Errors use a consistent {"error": {type, message}} envelope. Set REDCELL_API_KEY to require an x-api-key header on all routes except /health and /docs (no key set ⇒ open, for dev). Lock CORS to your frontend origin in prod via REDCELL_CORS_ORIGINS (comma-separated; default *).

Web app (frontend)

A modern dark "security console" UI (Vite + React + TypeScript + Tailwind + shadcn/ui) in web/ — Dashboard, Targets, Scans (+ live-polling detail, reports), Benchmark, and Adaptive pages, all over the REST API.

cd web
cp .env.example .env          # set VITE_API_BASE_URL (default http://localhost:8000)
npm install
npm run dev                   # http://localhost:5173  (run `redcell serve` alongside)

Deploy

  • API → Render / Railway / any container host via the root Dockerfile (uvicorn redcell.api.app:app). Set REDCELL_API_KEY and REDCELL_CORS_ORIGINS in prod. (SQLite is ephemeral on free tiers — mount a volume at /data for durability.)
  • Frontend → Vercel with root web/, build npm run build, output dist/, env VITE_API_BASE_URL = your deployed API URL. SPA routing handled by web/vercel.json.

Dashboard

A local web view of your scan history — per-target run trends, latest findings, and OWASP breakdown. The seed of the hosted-cloud layer.

redcell dashboard --history .redcell/history.jsonl   # then open http://localhost:8000

CTF demo (Gandalf-style)

A playable web demo: chat with a defended agent across escalating levels and try to social-engineer its secret out of it. Great for showing the problem to non-experts.

redcell ctf --provider groq        # then open http://localhost:8000

Backed by the same provider layer (free Groq/Ollama work). Win detection catches verbatim and whitespace-obfuscated leaks. Defensive/educational only — the secrets are throwaway words.

Design

attack  ──build_scenarios(canary)──▶  scenarios
scenario ──────target.run()────────▶  transcript (tool calls + final output)
transcript ─────judge.evaluate()───▶  verdict (success? evidence)
verdicts ──────────report──────────▶  HTML / JSON  (OWASP + NIST mapping)

The indirect-injection surface is modeled explicitly: a Scenario names the tool whose output the attacker controls, and the target substitutes that tool's return value with the payload — exactly the cross-surface vector that single-prompt scanners miss.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

redcell-0.1.0.tar.gz (29.7 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

redcell-0.1.0-py3-none-any.whl (93.7 kB view details)

Uploaded Python 3

File details

Details for the file redcell-0.1.0.tar.gz.

File metadata

  • Download URL: redcell-0.1.0.tar.gz
  • Upload date:
  • Size: 29.7 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.5

File hashes

Hashes for redcell-0.1.0.tar.gz
Algorithm Hash digest
SHA256 51f30be6d049a401fcfc7407f3fa9a8fcc488f2893f06d0e490a4fbb5d3426fe
MD5 63982370db1e18efc4f3dbe9deba5ed2
BLAKE2b-256 f5adddc91604bd557ffdff0791d425032ff7f7f956201616069513aecba9dbb4

See more details on using hashes here.

File details

Details for the file redcell-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: redcell-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 93.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.5

File hashes

Hashes for redcell-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e14f0d2c53e754e525ba7f38d59a9b4d67118b352c06a9f8ceee84ffbe92f3ce
MD5 03e237a1d852b9dadeb485bdaf4c9db4
BLAKE2b-256 8dfab04110cc44b9796476b5c19874b39c638ad04a55028c0944526437e7abb7

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page