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,
echoa 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 thescriptedattacker; a real Claude-powered attacker + target are wired and gated behindANTHROPIC_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 --provider → REDCELL_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/scanslaunches the given command on the host — running it executes the MCP server's code. Today it runs locally (setREDCELL_API_KEYand don't expose it on an untrusted network). For a hosted/multi-user deployment, route scans through the sandbox harness — the seam isservice.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). SetREDCELL_API_KEYandREDCELL_CORS_ORIGINSin prod. (SQLite is ephemeral on free tiers — mount a volume at/datafor durability.) - Frontend → Vercel with root
web/, buildnpm run build, outputdist/, envVITE_API_BASE_URL= your deployed API URL. SPA routing handled byweb/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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
51f30be6d049a401fcfc7407f3fa9a8fcc488f2893f06d0e490a4fbb5d3426fe
|
|
| MD5 |
63982370db1e18efc4f3dbe9deba5ed2
|
|
| BLAKE2b-256 |
f5adddc91604bd557ffdff0791d425032ff7f7f956201616069513aecba9dbb4
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e14f0d2c53e754e525ba7f38d59a9b4d67118b352c06a9f8ceee84ffbe92f3ce
|
|
| MD5 |
03e237a1d852b9dadeb485bdaf4c9db4
|
|
| BLAKE2b-256 |
8dfab04110cc44b9796476b5c19874b39c638ad04a55028c0944526437e7abb7
|