Scanner methodology
Every zn Scan score is a weighted fraction of applicable checks. This page defines the full check catalog, the tier weights, and the rules that keep the measurement neutral and reproducible. The rubric is versioned; every change is listed in the changelog below with its date, and each report states the rubric version it was scored with.
1. Passive only
Remote scans perform the MCP handshake (initialize, notifications/initialized) and tools/list over Streamable HTTP, within 15 seconds and on ports 443, 80 or 8443 only. No tool is ever invoked and no adversarial payload is sent to the target. If tools/list requires authentication, tool checks leave the denominator instead of failing, and the report shows how many checks were scored.
2. Applicability
A check the target cannot satisfy by design (no mutation tools, read-only server) is excluded from the denominator rather than scored as a failure. Score = earned weight / applicable weight. A letter grade needs at least one tool-level check: otherwise the report is Not rated.
3. Product neutrality
No check rewards a specific product. zn-gate appears only as one of several remediation options, always listed next to an open-source alternative. Every grade from A+ to F is reachable without any purchase.
Grade bands
| Grade | Score | Meaning |
|---|---|---|
| A+ | 95–100 | Highly Resilient |
| A | 85–94 | Strong Baseline |
| B | 70–84 | Moderate Risk |
| C | 50–69 | Elevated Risk |
| F | < 50 | Critical Vulnerability |
| NR | — | Not rated: no tool-level check could be scored (auth-gated endpoint, legacy SSE transport or no tool schema). Observed checks are still listed. |
Essential tier
12 pts eachBasic security. Missing controls score as failures.
TLS 1.2+ transport encryption
RFC 5246 / RFC 8446tls_transportEndpoints reachable over HTTPS with a valid certificate chain for the hostname. Cleartext HTTP transport fails.
Fix: Terminate TLS at the edge with a managed certificate and redirect all cleartext requests.
Open-source alternative: Let's Encrypt + Caddy or Nginx certbot with HSTS.
Authenticated transport boundary
MCP Authorizationauth_boundaryMCP endpoints that expose mutation-capable tools enforce an auth boundary (OAuth 2.1 with PKCE or signed bearer tokens) before serving them.
Fix: Require OAuth 2.1 authorization-code flow with PKCE on every MCP transport endpoint.
Open-source alternative: Open-source identity providers (Keycloak, Ory Hydra, oauth2-proxy) expose the same flows.
Input bounds and payload limits
OWASP LLM10input_boundsDeclared string parameters include max lengths, enums, or patterns so a single call cannot carry unbounded payloads.
Fix: Constrain string parameters with maxLength, enum or pattern and reject oversize bodies at transport level.
Open-source alternative: JSON Schema maxLength plus framework-level body size guards (e.g. express body-parser limits).
Tool description hygiene
OWASP LLM01tool_desc_hygieneTool and parameter descriptions scanned for adversarial imperatives and invisible Unicode buried in docstrings (indirect tool poisoning).
Fix: Rewrite descriptions as neutral capability statements; strip imperative clauses and invisible characters.
Open-source alternative: mcp-scan (Invariant Labs) and LlamaFirewall both flag poisoned descriptions.
No unconstrained shell primitives
OWASP LLM06shell_primitivesTools exposing arbitrary shell, eval, or command execution on the host without sandboxing are critical by design.
Fix: Replace open shell tools with granular scoped operations or run them inside a sandbox (Docker, Firecracker).
Open-source alternative: Firecracker microVMs, gVisor, or Docker with read-only rootfs and dropped capabilities.
Filesystem mutation bounded
OWASP LLM06fs_mutationFile write or delete tools must bound their path parameters (pattern, length or a declared sandbox root). Unscoped paths fail.
Fix: Bind the server to a single workspace root with respect for hidden-file exclusions.
Open-source alternative: The reference MCP filesystem server scopes roots the same way.
No plaintext credential parameters
OWASP LLM02credentials_exposureTool parameters must not accept API keys, passwords, or tokens as model-visible arguments.
Fix: Inject credentials at runtime from the environment or a secret manager, never through tool arguments.
Open-source alternative: Vault, AWS Secrets Manager, or Doppler with env-scoped injection.
Recommended tier
6 pts eachGood practice for exposed servers. Failures subtract weight.
Strict parameter schema typing
OWASP LLM05param_typingEvery tool declares an object inputSchema and every declared parameter has an explicit type. Tools without arguments pass; schemas missing or typed as open bags fail.
Fix: Declare types (string, integer, boolean) and required fields in every tool inputSchema.
Open-source alternative: Zod, Pydantic, or vanilla JSON Schema generate strict schemas the same way.
Human gate on high-stakes mutations
OWASP LLM06financial_human_gateIrreversible actions (refund, transfer, charge, deploy) require an auditable human approval step. Not observable passively: reported for manual verification, never scored.
Fix: Add a two-step confirmation flow with server-side approval tokens for mutation tools.
Open-source alternative: Any webhook-based approval queue (Slack bot, Linear flow) implements the same gate.
Tool-output filtering capacity
OWASP LLM01output_filter_capacityThe target must show some mechanism to inspect or filter content returned by tools before it reaches the model, regardless of vendor.
Fix: Filter tool outputs inline (neural gate, regex policy, or framework middleware) before re-injecting into context.
Open-source alternative: LlamaFirewall, LLM Guard, or Azure Prompt Shield provide equivalent capacity.
Tool namespace isolation
OWASP LLM01namespace_isolationContext cannot redefine, shadow, or override registered tool names from untrusted documents.
Fix: Rebuild the tool registry each turn and reject shadowed names.
Open-source alternative: The reference MCP SDK keeps client-controlled tool names immutable.
Bonus tier
2 pts eachExtra credit. If absent by design, the check is excluded from the denominator: it never subtracts.
Zero data retention policy published
OWASP LLM02zdr_policyA published, linkable statement about what the server retains from tool calls or conversations.
Fix: Publish a data-retention statement on the site.
Open-source alternative: A public docs page or trust report satisfies this without any vendor.
Cryptographic audit trail
OWASP LLM06audit_trailVerdicts and mutations produce hash-chained or signed evidence records.
Fix: Log verdicts with hash chaining or append-only storage.
Open-source alternative: Hash-chained logs with OpenSSL or an append-only Merkle log implement this pattern.
Remote scan mechanics
- DNS resolution is validated before every connection; requests pin one resolved address (no DNS rebinding window).
- Private, loopback, link-local (including 169.254.169.254), CGNAT, multicast, and documentation ranges are rejected at DNS time and again per redirect hop.
- Maximum 2 redirects, at most 8 seconds per request, a 15 second budget for the whole scan, 512 KB response cap per request.
- An HTTP 401 or 403 counts as an MCP auth challenge only with a WWW-Authenticate: Bearer header, RFC 9728 protected-resource metadata or a JSON-RPC error body. Auth-gated servers are reported as Not rated, never as A+ on transport alone.
- Rate limit: 20 scans per hour per source IP.
- Targets that do not answer as an MCP server (unreachable, or HTTP responses that are not MCP) are reported back to the user only; nothing is published.
- TLS certificates must validate against the scanned hostname (SNI, full chain).
- Every report carries per-check evidence and its own URL (scan.usezn.com/r/{id}/) with JSON, Markdown, and badge variants, so any score can be re-verified by running the same scan again. Reports are not indexed by search engines and are deleted after 90 days.
Static mode (pasted artifacts)
Pasted system prompts and tool schemas are analyzed in the browser and never uploaded. The same lexicons and tier weights apply; transport checks are excluded from the denominator because pasted artifacts cannot carry them. A pasted system prompt without a tool schema is Not rated. This mode proves what the artifacts themselves declare, nothing more.
Normative references
- TLS 1.2 (RFC 5246) / TLS 1.3 (RFC 8446).
- Model Context Protocol (2025-06-18): initialize, tools/list, Streamable HTTP, Authorization (OAuth 2.1).
- OAuth 2.0 Protected Resource Metadata: RFC 9728.
- OWASP Top 10 for LLM Applications (2025): LLM01 Prompt Injection, LLM02 Sensitive Information Disclosure, LLM05 Improper Output Handling, LLM06 Excessive Agency, LLM10 Unbounded Consumption.
Changelog
v1.1
2026-10-10- Not rated (NR): a letter grade now requires at least one tool-level check. Auth-gated endpoints, legacy SSE servers and empty tool lists are reported as Not rated instead of earning A+ on transport alone.
- Auth detection: an HTTP 401/403 counts as an MCP auth challenge only with a WWW-Authenticate: Bearer header, RFC 9728 protected-resource metadata or a JSON-RPC error body; a bare 403 from a firewall is not an MCP server and is not published.
- Fewer false positives: credential parameters are matched on whole name segments (author, max_tokens and page_token no longer match); tools without arguments pass schema typing; filesystem checks only apply to file-shaped tools; shell detection needs a shell/eval/command-execution name, or a description of arbitrary command or code execution.
- Tool description hygiene also inspects parameter descriptions and flags invisible Unicode (zero-width, bidirectional and tag characters).
- References corrected to the OWASP Top 10 for LLM Applications 2025 (LLM01, LLM02, LLM05, LLM06, LLM10) and the MCP authorization spec.
- Duplicate auth and transport rows removed from reports.
v1.0
2026-09-30- First public rubric: 13 checks in three tiers, applicability exclusions, passive remote mode and in-browser static mode.
Reports keep the rubric version they were scored with. Run the scan again to get a score under the current version. The changelog is published in English.
Disputes and corrections
Think a check is wrong for your server? Email security@usezn.com with the scan id (scan_…, shown on every report) and what you believe is inaccurate. Confirmed rubric errors are fixed in a new rubric version listed in the changelog above. Server owners can also ask for a published report about their server to be removed. security@usezn.com