Active, confirmation-driven security scanner for MCP (Model Context Protocol) servers - Burp Active Scan, for MCP.
Project description
mcpsnare
The active security scanner for MCP servers — Burp Active Scan, for the Model Context Protocol.
mcpsnare enumerates the tools an MCP server exposes, fires targeted payloads at their parameters, and reports only what it can prove. Every finding is tied to a concrete oracle — an out-of-band callback, a reflected canary, a calibrated timing delay — and carries a graded confidence level.
Most "MCP security" tools pattern-match configs and source code. mcpsnare triggers the
vulnerability and catches the proof: a CONFIRMED finding is exploitable, not theoretical.
(Formerly published as
mcprobe.)
Demo
A default scan of a vulnerable MCP server — no config, one command:
$ mcpsnare scan --stdio "python vulnerable_server.py"
[!] mcpsnare - authorized testing only.
6 finding(s):
[HIGH] Path traversal in read_doc.path (confirmed)
[HIGH] Secret/info leak via whoami (firm)
[HIGH] Path traversal in read_cfg.config.path (confirmed)
[HIGH] Path traversal in read_many.paths[0] (confirmed)
[HIGH] Path traversal in read_mode.path (confirmed)
[CRITICAL] Command injection in ping.host (confirmed)
That CRITICAL command injection is confirmed because the injected payload made the
target call back to a listener mcpsnare controls — an out-of-band proof of execution,
not a guess. The same scan as machine-readable JSON (or SARIF / Markdown):
$ mcpsnare scan --stdio "python vulnerable_server.py" --output json
{
"summary": { "critical": 1, "high": 5, "medium": 0, "low": 0, "info": 0 },
"findings": [
{
"check": "path_traversal", "tool": "read_doc", "param": "path",
"severity": "high", "confidence": "confirmed", "cwe": "CWE-22",
"title": "Path traversal in read_doc.path",
"payload": "../../../../../../etc/passwd",
"evidence": "root:x:0:0:root:/root:/bin/bash",
"remediation": "Resolve and contain paths within an allowed base dir."
}
/* ... */
]
}
Install
From source (Python 3.11+):
git clone https://github.com/Den-Sec/mcpsnare && cd mcpsnare
pip install -e ".[dev]"
This installs the mcpsnare console entry point. A PyPI release (pipx install mcpsnare)
is imminent — see Releases.
Quickstart
# Local stdio server (launched as a subprocess)
mcpsnare scan --stdio "python server.py"
# Remote streamable-HTTP endpoint, with auth, emitting SARIF for code scanning
mcpsnare scan --http https://host/mcp --header "Authorization: Bearer X" --output sarif
# Add blocking time-based probes (off by default) and tune concurrency
mcpsnare scan --stdio "python server.py" --aggressive --concurrency 8
Why mcpsnare
Most MCP security tooling is either a generic fuzzer (noisy, low-signal) or a defensive/static analyzer (reads config and source, never proves exploitability). mcpsnare is built around active confirmation:
- Oracle-backed, not guesses. Every finding is tied to a concrete signal: an out-of-band (OOB) callback, a calibrated time delay, a canary value reflected in the response, or a baseline diff. No signal, no finding.
- Graded, calibrated confidence. Findings carry an explicit confidence level (CONFIRMED / FIRM / TENTATIVE, see Confidence levels). Per-tool baseline calibration suppresses the usual false-positive classes — a slow-but-safe tool, or output that merely looks secret-shaped, is not flagged.
- Reaches real schemas. Maps injection points through nested objects, array items, and params gated behind required enums; builds schema-valid baselines so payloads actually reach the handler.
- Both transports. Works against MCP servers over stdio (local process) and streamable HTTP (remote endpoint, with custom headers/auth) — both exercised end-to-end in CI on Linux and Windows.
Confidence levels
Every finding carries one of three confidence levels, each earned by a specific oracle:
| Level | Meaning | How it's earned |
|---|---|---|
| CONFIRMED | The payload provably executed, or protected data was reached. | An out-of-band callback fired (cmd injection, SSRF), a canary value was read back (path traversal), or an unauthenticated call returned a response byte-identical to the authenticated one (auth bypass). |
| FIRM | A calibrated/inferred signal strongly indicates the issue, short of an OOB proof. | A response delay exceeds the per-tool calibrated baseline by the injected sleep (time-based cmd injection); a secret-shaped string appears in the probe response but not in the benign baseline (info leak); or an unauthenticated response matches the authenticated one only after stripping volatile fields like timestamps/ids (auth bypass). |
| TENTATIVE | Pattern-only match, with no calibration to corroborate it. | A secret-shaped string matched, but no baseline was available to prove the input triggered it — review manually. |
The OOB and canary checks emit only CONFIRMED. Auth-bypass emits CONFIRMED on a byte-identical response or FIRM on a match after stripping volatile fields. The timing and info-leak oracles are where FIRM and TENTATIVE arise.
Checks
| Check | Vulnerability | CWE |
|---|---|---|
cmd_injection |
OS command injection | CWE-78 |
ssrf |
Server-side request forgery | CWE-918 |
path_traversal |
Path traversal | CWE-22 |
auth_bypass |
Missing authentication | CWE-306 |
info_leak |
Secret / sensitive info leak | CWE-200 |
sql_injection |
SQL injection | CWE-89 |
mcpsnare also enumerates MCP resource templates and treats their templated URI
params (e.g. file:///{path}) as injection points for path-traversal and info-leak.
Out-of-band (OOB) confirmation
OOB callbacks are how mcpsnare confirms blind command injection and SSRF: a probe makes the target reach back to a listener mcpsnare controls.
--oob local(default) spins up an in-process HTTP listener on localhost. It needs no external service and works for targets that can reach your machine (typically local stdio servers).--oob interactshuses an out-of-band interaction server for targets that cannot reach localhost (e.g. remote HTTP servers). mcpsnare ships a real interactsh client (RSA-OAEP / AES-256-CTR), so this works out of the box against the publicoast.fun(override with--interactsh-server); it was live-verified end to end. See docs/interactsh-runbook.md.--oob nonedisables OOB confirmation; only time-based and canary oracles run.
Flags
--stdio "<cmd>"/--http <url>— target transport (one required).--header "k:v"— add an HTTP header (repeatable).--oob {local,interactsh,none}— OOB confirmation backend (localdefault).--aggressive— also send blocking time-based (sleep) probes; by default mcpsnare sends only non-blocking OOB/canary/pattern probes (time-based detection is aggressive-only).--concurrency N— max concurrent probe requests (default 4). Time-based probes run serially.--rate R— cap to R requests/second (default unlimited).--oob-timeout S/--oob-poll-interval S— how long (default 20s) / how often (default 2.5s) to poll for OOB callbacks.--output {console,json,sarif,md}— output format (defaultconsole).
Authorized testing only
mcpsnare is an active scanner. It sends real, potentially destructive payloads to the target. Run it only against systems you own or have explicit written authorization to test. Unauthorized use may be illegal. You are responsible for how you use this tool.
Validation
mcpsnare is validated by an automated test suite (119 tests) against bundled
deliberately-vulnerable fixture servers in tests/fixtures/. The suite exercises
command injection (including cross-OS cmd.exe / PowerShell payloads), SSRF, path
traversal, info-leak, SQL injection, nested/array/enum injection points, and the OOB,
baseline-calibration, and false-positive-suppression paths end to end — over both
stdio and a live in-process streamable-HTTP server, on Linux and Windows in CI. See
docs/claims-matrix.md for the claim-to-test mapping.
It has also been smoke-tested against the real @modelcontextprotocol/server-everything
reference server (13 tools, 2 resource templates) — clean run, zero false positives. See
docs/smoke-run.md.
Roadmap
- MCP-specific checks: tool-poisoning / prompt-injection via tool descriptions, and tool-scope / permission-boundary violations.
- Additional OOB providers and richer time-based oracles.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
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 mcpsnare-0.3.0.tar.gz.
File metadata
- Download URL: mcpsnare-0.3.0.tar.gz
- Upload date:
- Size: 39.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
95623a1b31a2b710ba58ae63f90d7ec573faf35bf03830b75c0e67473dc7f52e
|
|
| MD5 |
3f2af3683066a53e751746f1037400e7
|
|
| BLAKE2b-256 |
9f9c5ec49d8c22276636e9c2e51e7b5638c09a958e256218f3d578750dac7817
|
Provenance
The following attestation bundles were made for mcpsnare-0.3.0.tar.gz:
Publisher:
release.yml on Den-Sec/mcpsnare
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcpsnare-0.3.0.tar.gz -
Subject digest:
95623a1b31a2b710ba58ae63f90d7ec573faf35bf03830b75c0e67473dc7f52e - Sigstore transparency entry: 1790872738
- Sigstore integration time:
-
Permalink:
Den-Sec/mcpsnare@999bd06ea001425c288454f8ef19df8476c35bc9 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/Den-Sec
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@999bd06ea001425c288454f8ef19df8476c35bc9 -
Trigger Event:
release
-
Statement type:
File details
Details for the file mcpsnare-0.3.0-py3-none-any.whl.
File metadata
- Download URL: mcpsnare-0.3.0-py3-none-any.whl
- Upload date:
- Size: 29.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
83dbcac2ea43c8a1e54fb0ed832ed79cc584f65c514fe922a169b691de8ad3f4
|
|
| MD5 |
aa1cbff8fe58d778aab8b219028ff09a
|
|
| BLAKE2b-256 |
f438823ec0d59a4d12145ecc4ac0a229b46e1a6b523f606336ef7b08efff0d59
|
Provenance
The following attestation bundles were made for mcpsnare-0.3.0-py3-none-any.whl:
Publisher:
release.yml on Den-Sec/mcpsnare
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcpsnare-0.3.0-py3-none-any.whl -
Subject digest:
83dbcac2ea43c8a1e54fb0ed832ed79cc584f65c514fe922a169b691de8ad3f4 - Sigstore transparency entry: 1790872755
- Sigstore integration time:
-
Permalink:
Den-Sec/mcpsnare@999bd06ea001425c288454f8ef19df8476c35bc9 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/Den-Sec
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@999bd06ea001425c288454f8ef19df8476c35bc9 -
Trigger Event:
release
-
Statement type: