In an April 2026 audit, 27 detections from MCP security scanners boiled down to 6 genuine concerns. The scanners weren't missing attacks — they were crying wolf, which in a CI pipeline is the same failure wearing a different coat.
So I built a scanner whose first feature is its own error profile: every rule publishes a measured precision from a labelled corpus of planted positives and near-miss traps. This is how it works, what it catches — tool poisoning, rug pulls, dangerous sinks, hardcoded secrets — and where its numbers say it still gets things wrong.
One command before you install
Sentinel Scan is a security and conformance scanner for MCP servers and SKILL.md agent skills. One command scans a server or skill for tool poisoning, rug pulls, dangerous code sinks, and hardcoded secrets — and reports each rule's measured precision rather than just asserting it.
pip install sentinel-scan sentinel-scan demo The demo scans the bundled 12-tool corpus in about a second: 6 benign tools — two of them near-miss traps — and 6 with planted findings, producing 7 findings. The two traps produce no findings: a tool that "ignores previous cached results" and a security tool that quotes an injection as an example. That restraint is the product.
Pure Python, no API keys, no GPU, no network. Python ≥ 3.10.
What it catches
- Tool poisoning: hidden instructions in tool descriptions — markup directives, "note to the AI" framing, ignore-instruction phrasing — plus descriptions that direct credentials, files, or conversation contents out, and covert actions a tool takes "without telling the user."
- Rug pulls: a tool's description changing after you pinned it. Sentinel Scan stores a SHA-256 pin of the normalized description and flags quiet changes (whitespace-only edits ignored).
- Dangerous sinks: command execution (
shell=True,os.system, string commands — fixed argv withshell=Falsedoes not fire), dynamic code (eval/exec—ast.literal_evaldoes not fire), and sensitive-file access (~/.ssh,~/.aws,/etc/passwd, key files, full environment dumps — a comment merely mentioning a path does not fire). - Hardcoded secrets: AWS key ids, GitHub tokens, OpenAI-style keys, private-key blocks, assigned credential literals (
${VAR}references do not fire). - Skill rules: hidden instructions in a SKILL.md body, capabilities the body uses but the frontmatter does not declare, and filesystem servers scoped to
/,~, or a home directory instead of a project directory.
Measured, not asserted
Each rule is deliberately narrow: it fires on a specific, explainable signal shape. The rates are measured with scripts/measure.py over the labelled corpus in fixtures/corpus/ — 32 cases of planted positives and benign near-miss negatives for every rule. Across all rules: 18 true positives, 0 false positives, 0 false negatives.
Those are corpus rates, not a promise about the open internet. Re-run the measurement yourself:
python3 scripts/measure.py Using it
Scan an MCP config, a tools manifest, server sources, or skill folders:
sentinel-scan scan ~/.config/... Exit codes are CI-shaped: the scan exits 1 when any finding is at or above --fail-on (default high). Outputs are terminal text, JSON, and SARIF, which renders in the GitHub Security tab. There is also a GitHub Action (ranadhir19/sentinel-scan@v0.1.0) that runs the scan, writes SARIF, and uploads it to the Security tab.
What it does not do: no dynamic execution of scanned servers, no LLM judgement calls, no network calls. It is static analysis. There is also a local web demo in demo/ (React front end, FastAPI backend) if you want to paste a description, a SKILL.md body, or source and watch it scan.