A reference table for the 10 static mcp.json manifest heuristics we use, mapped to both the OWASP MCP Top 10 (beta) and the existing OWASP LLM Top 10. Pulled verbatim from the scanner's own code, not guessed after the fact.
A lot of MCP-specific findings don't have a clean home yet in an existing framework. The OWASP MCP Top 10 (beta) is trying to fix that, but most of the write-ups mapping real findings onto it are thin. Below is the actual mapping we use in sentinel-scan-cli's static mcp.json manifest scanner: each heuristic, what it catches, and which OWASP MCP Top 10 and OWASP LLM Top 10 categories it maps to.
This is reference material first. If you're auditing your own MCP configs, building similar tooling, or just trying to figure out where a given misconfiguration class fits in the OWASP frameworks, the table should be useful on its own regardless of what scans it.
| Heuristic | OWASP MCP Top 10 | OWASP LLM Top 10 | What it catches |
|---|---|---|---|
tool_description_injection | MCP01: Prompt Injection via Tool Descriptions | LLM01 | imperative/override language, fake system tags, zero-width chars, base64 blobs hidden in a tool's description field |
hidden_unicode_instructions | MCP01 | LLM01 | invisible unicode steering text inside descriptions (tag-block smuggling, bidi overrides) |
tool_name_shadowing | MCP02: Tool Poisoning / Shadowing | LLM01 | tool names that collide with sensitive/builtin names, or descriptions claiming to override another tool |
indirect_injection_surface | MCP01 | LLM01 | manifests that both ingest untrusted content (fetch/browse/read-inbox) and can act (send/write/execute), the toxic-flow combo |
hardcoded_credential | MCP03: Credential / Secret Exposure | LLM02 | API keys/tokens/passwords literal in a server's env block or CLI args instead of an env-var placeholder |
unpinned_remote_source | MCP04: Supply Chain Risk | LLM03 | npx/uvx/pip server entries with no pinned version, or plaintext http:// transports |
missing_provenance | MCP04 | LLM03 | remote-sourced server entries with no signature/checksum/publisher field |
excessive_agency_schema | MCP06: Excessive Agency / Permissions | LLM06 | free-form shell/command params, admin/bypass/sudo flags, wide-open schemas |
overbroad_tool_scope | MCP06 | LLM06 | wildcard/blanket scopes ("*", "all", "admin") instead of enumerated lists |
missing_hitl_confirmation | MCP06 | LLM06 | sensitive-capability tools (exec, filesystem write/delete, outbound send) with no human-in-the-loop gate |
Note that only three OWASP MCP Top 10 categories show up: MCP01 (prompt injection via tool descriptions), MCP02 (tool poisoning/shadowing), MCP03 (credential exposure), MCP04 (supply chain), and MCP06 (excessive agency). That's not a gap in the table, it's a real limit of what a purely static, offline manifest scan can see. Categories like runtime tool poisoning after install, cross-origin session hijacking, or DoS need a live server connection to detect at all, a static text/JSON parse of the manifest structurally can't reach them.
This table is pulled directly from the OWASP_MCP_TOP10 dict in the scanner's source, cross-checked against the heuristic comment block above it. No category was assigned from memory or inferred after the fact, every code here traces to a specific line in the repo:
OWASP_MCP_TOP10 = {
"tool_description_injection": "MCP01: Prompt Injection via Tool Descriptions",
"tool_name_shadowing": "MCP02: Tool Poisoning / Shadowing",
"excessive_agency_schema": "MCP06: Excessive Agency / Permissions",
"indirect_injection_surface": "MCP01: Prompt Injection via Tool Descriptions",
"unpinned_remote_source": "MCP04: Supply Chain Risk",
"hardcoded_credential": "MCP03: Credential / Secret Exposure",
"overbroad_tool_scope": "MCP06: Excessive Agency / Permissions",
"missing_provenance": "MCP04: Supply Chain Risk",
"missing_hitl_confirmation": "MCP06: Excessive Agency / Permissions",
"hidden_unicode_instructions": "MCP01: Prompt Injection via Tool Descriptions",
}
The scan is offline, static analysis only, no network calls, no server execution, just parsing the manifest text and JSON structure.
pip install sentinel-scan-cli
sentinel-scan mcp --demo
or, no install:
pipx run sentinel-scan-cli mcp --demo
Point it at your own mcp.json once you've seen the demo output. It's open source (MIT): github.com/Ventrova/sentinel-scan-cli.
Source of mapping: sentinel_scan.py, OWASP_MCP_TOP10 dict, cross-checked against the heuristic comment table in the same file. Verified 2026-08-24.