Autopsy 08 · MCP trust boundary · Comic Strip 6 A free MCP from the internet!

Would Ethosure have caught this?  The Sentry MCP server SSRF

A self-hosted Sentry MCP server accepted a caller-controlled endpoint argument and passed it directly to an HTTP client. Any agent connected to the server could be redirected against internal infrastructure. The fix is not one CVE. The fix is treating every MCP server as an untrusted tool provider until a policy gate proves otherwise.

Series: Would Ethosure have caught this?
Root cause: MCP tool input trusted by default
Coding-ethos policy: mcp.tool_call.destination_allowlist

The incident

On July 12, 2026 an independent researcher opened GitHub issue #2 on the ddfourtwo/sentry-selfhosted-mcp repository, reporting a server-side request forgery in the raw_sentry_api component. The vulnerability is tracked as CVE-2026-81421. The raw_sentry_api tool accepted a caller-controlled endpoint argument and passed it directly to Axios request methods without validation; Axios processes absolute URLs, so a JSON-RPC call could set the endpoint to a local address such as http://127.0.0.1:8000/ssrf-proof and force the MCP server to initiate an outbound request to any destination. Tenable assigned CVSS 7.3; researchers argue 9.0. Forty-six days passed between the initial report and the CVE assignment with no maintainer response. Related work reported public Sentry DSNs usable as an attack vector against AI agents with an 85 percent success rate across 2,388 organisations.

The applicable coding-ethos policy

Policy packModel / provider governance pack (financial services overlay inherits)
Principletool-provider-untrust
Control familyMCP trust boundary + tool-input validation

Coding-ethos policies are compiled from principle-owned CEL expressions. Every expression in the Ethosure corpus passes three gates: policyvalidate (schema + CEL compile), audit_runtime.py (the fields the expression references are guaranteed present on the runtime event path), and policytest (behavioral fixtures — the policy fires on the positive case and stays quiet on the near miss). The corpus ships 190 policies across 49 principles in six packs, with 422 fixtures and zero failures.

READ  Would Ethosure have caught this? Check Point’s eleven flaws across every major agent framework

Walkthrough

  1. The vulnerability class is old — SSRF against an HTTP client that accepts absolute URLs. What is new is the surface. MCP servers are how agents pick up tools at runtime. Most enterprises do not yet treat them as untrusted third-party code. The policy answer is to require every MCP tool invocation to declare its destination and to check that destination against an allowlist before the call leaves the runtime.
  2. mcp.tool_call.destination_allowlist fires on PreToolUse for any MCP tool invocation whose resolved destination — including URLs reachable through tool-input parameters — is not on the workload’s allowlist. It returns severity block. This is a runtime gate: the MCP server’s own input validation is treated as untrusted.
  3. mcp.server.provenance_required is the companion. The Sentry case is the pattern: a community maintainer, no signed release process, forty-six days of silence on a public issue. The expression fires when an agent attempts to register a new MCP server whose publisher identity is not on the trust list or whose latest release is not signed by a key in the registry.
  4. mcp.tool_input.no_absolute_url_in_endpoint_argument is the direct class-of-attack policy. The expression fires on any tool call whose input contains a parameter named endpoint, url, uri, or target whose value parses as an absolute URL to a destination outside the workload’s allowlist. This closes the exact primitive Axios used to reach internal infrastructure.

Policy YAML

# Pack: model-provider-governance (v2)
# Inherits: regulated-enterprise-base
principles:
  - id: tool-provider-untrust
    title: Tool Provider Untrust
    directive: >-
      Treat every MCP server as an untrusted tool provider. Validate destinations,
      require publisher provenance, and reject caller-controlled absolute URLs in
      endpoint arguments.
    policy:
      expressions:
        - id: mcp.tool_call.destination_allowlist
          scope: agent_action
          severity: block
          event: PreToolUse
          principle_ids:
            - tool-provider-untrust
            - security-by-design
          skill_id: mcp-runtime-gating
          when: >
            tool_call.transport == "mcp"
            && !workload.egress_allowlist.exists(a,
                 tool_call.resolved_destination.matches(a))
          message: >-
            MCP tool call resolved to a destination outside the workload's allowlist.
          advice: >-
            Add the destination to the workload allowlist with a signed change entry, or reject
            the call. The MCP server's own input validation is not authoritative.

        - id: mcp.server.provenance_required
          scope: agent_config
          severity: block
          event: MCPServerRegister
          principle_ids:
            - tool-provider-untrust
            - radical-visibility
          when: >
            !registry.publishers.exists(p, p.id == mcp_server.publisher_id)
            || !mcp_server.latest_release.signed_by.exists(s,
                 registry.trusted_keys.exists(k, k == s))
          message: >-
            MCP server registration lacks a trusted publisher or a signed release.
          advice: >-
            Reject the registration until the publisher is added to the trust registry and the
            release is signed by a trusted key. Community MCP servers without a signed release
            process are treated as untrusted.

        - id: mcp.tool_input.no_absolute_url_in_endpoint_argument
          scope: agent_action
          severity: block
          event: PreToolUse
          principle_ids:
            - tool-provider-untrust
            - security-by-design
          when: >
            tool_call.transport == "mcp"
            && tool_call.input_params.exists(p,
                 p.name in ["endpoint", "url", "uri", "target"]
                 && p.value.is_absolute_url
                 && !workload.egress_allowlist.exists(a, p.value.matches(a)))
          message: >-
            MCP tool input contains a caller-controlled absolute URL outside the allowlist.
          advice: >-
            Reject absolute URLs in endpoint-shaped arguments. The Sentry MCP SSRF used exactly
            this primitive to force outbound requests to internal addresses.

Assurance boundary. Fixtures prove that synthetic positive cases fire and near-misses stay quiet. They do not establish production alert rates. DLP-backed controls depend on upstream detection, shell-command regexes are defense in depth rather than a sandbox boundary, and regulatory tags are engineering aids requiring counsel review.

READ  What is SARIF? The Common Language for "What the Checks Found"

Where this policy lives in the corpus

The Ethosure importable corpus ships six coding-ethos packs. Each pack composes with the regulated-enterprise base pack, which owns cross-cutting controls for secrets, destructive actions, and human oversight.

  • Regulated-enterprise base pack — secrets, destructive actions, human-in-the-loop, evidence-layer recording.
  • Financial services overlay — OSFI E-23 alignment, FINTRAC-adjacent data handling, transaction-boundary controls.
  • Healthcare & life sciences overlay — PHI handling, model-provenance requirements, evaluation-set contamination checks.
  • Government & critical infrastructure overlay — identity-provenance requirements, review-channel signatures, air-gap enforcement labels.
  • Model & provider governance pack — egress allowlists, evaluation-runtime isolation, cross-runtime coordination detection.
  • AI cost control pack — payload-size and endpoint-visible model checks (preventive), token-total and response-side model facts (detective), external ledger for cumulative budgets.

Published September 3, 2026 · Ethosure · Part of the Autopsy Series.

Subscribe to Ethosure's Newsletter to get monthly updates on AI Governance

We don’t spam! Read our privacy policy for more info.