Repository navigation
The passive lens flagged an execute_revit_code-style tool; the active checks couldn't
confirm it, because shell metacharacters are a SyntaxError inside a language interpreter.
And a bare results: [] couldn't be told apart from "nothing was actually tested". This
release closes both — and adds a check that speaks the sink's language.
Highlights
-
Active code / eval-sink injection (
code_injection, CWE-94). Injects language-native
payloads — CPythonurllib, Python 2 / IronPythonurllib2, Noderequire('http')— each
with its own out-of-band token, plus an arithmetic canary (7*7→49) whose evaluation is
reflected in the response. CONFIRMED on an OOB callback, FIRM on the canary absent from
the benign baseline, TENTATIVE without a baseline; atime.sleepvariant is
--aggressive-only. Gated to code-shaped parameter names. A bundledcode_serverfixture (a
realeval/execsink) confirms it in CI — a payload really opens a socket to the local
listener, no Revit needed. This turns a declared code-exec tool from flagged into confirmed. -
Scan metadata in every report (
ScanResult). Reports now carry target, transport, tools
discovered vs. reachable, checks run,--aggressive, and how many injection points skipped the
blocking time-based probes — so an emptyfindingsis distinguishable from an untested scan
(JSONscan, SARIFinvocations, a Markdown "Scan metadata" section; a console header on the CLI). -
Free-form container coverage. Injection-point mapping now reaches values inside open maps —
additionalProperties, a baredict,list[dict]— so amodify_element(parameters: dict)
tool is probed via a synthesized canary key instead of skipped. Structured objects untouched. -
Unauthenticated-privileged-proxy note (
privileged_proxy, CWE-306, INFO). When the manifest
declares a CRITICAL/HIGH capability and the scan reached the tools with no credential presented,
the note flags the surface to vet — honestly stating the auth boundary was not verified, never
that it's absent.
Also
- Confidence-aware dedup: a later, stronger oracle (a deferred OOB CONFIRMED) upgrades an
earlier weaker finding for the same issue instead of being dropped. - Real-OS-shell validation: cmd-injection is now OOB-confirmed against a real shell (cmd.exe on
Windows,/bin/shon POSIX) on the CI matrix, closing the "fake-shell only" caveat for the
common (non-PowerShell) shell path.
Fixed (found by scanning real servers)
- Crash on tools-only servers.
resources/templates/listis optional in the MCP spec; a
tools-only server (most real servers) answers "Method not found". mcpsnare treated that as fatal
and aborted the whole scan — it now tolerates it and continues. - Ungraceful start failure. A server that exits before the MCP handshake (missing credentials,
bad command) now yields a clean error + non-zero exit instead of a raw traceback.
52 new tests; suite is now 191 green across Linux + Windows CI. No breaking changes to callers
or report consumers. Every public claim is mapped to a passing test in
docs/claims-matrix.md.
Field-tested: run against real official @modelcontextprotocol servers — it confirmed an
unauthenticated SSRF in the reference server, kept zero false positives (the filesystem
sandbox held against path-traversal), and the two fixes above came straight out of that run. The
honest field report is in
docs/real-world-scan-2026-07.md.
Install / upgrade: pipx install mcpsnare (or pip install -U mcpsnare).