Skip to content

v0.2.0 — security controls for a federating gateway

Latest

Choose a tag to compare

@wellknownmcp wellknownmcp released this 20 Jul 11:18

A gateway that federates N backends sees things a single MCP server does not: every backend's tool definitions, the transport to each of them, and the full call path from agent to application. This release adds the controls that follow from that position. All of them are documented, with their limits, in docs/security.md.

Tool definition integrity (rug-pull detection)

A backend that rewrites an approved tool's description or inputSchema keeps the name — the client's approval still looks valid while the model reads different instructions. The gateway now fingerprints scope, description, params, inputSchema, version and deprecated at first sight and re-checks them at every refresh, reporting added / removed / mutated with the changed field names. Key order is normalized, so a reserialized schema is not a false positive.

CORTEX_TOOL_INTEGRITY_MODE=warn    # default: log + push tools/list_changed, serve the new definition
CORTEX_TOOL_INTEGRITY_MODE=block   # quarantine: withheld from tools/list, refused at tools/call

In block mode the baseline keeps the approved definition, so a mutation stays reported instead of quietly becoming the new normal. A backend absent from a refresh is not treated as a withdrawal unless it actually answered — otherwise going briefly unreachable would launder a rewritten definition into a fresh approval.

The baseline lives in the process and is rebuilt at boot: this is mutation detection during a process's lifetime, not attestation. A persistent, operator-signed baseline is the next step.

Outbound transport policy

Every federated call forwards the caller's bearer token. Plaintext HTTP to a remote host is now refused at load — the backend is dropped with an error while the others keep serving. Loopback stays allowed (stdio bridge, local development). CORTEX_ALLOW_INSECURE_BACKENDS=true opts out for a private network with transport security at another layer, and warns on every load.

The same policy applies to URLs the gateway did not choose: in the adapter's discovery path (RFC 9728 → RFC 8414), the issuer and the authorization / token / registration endpoints all come from the remote server's metadata. Each is validated before use, and a discovered endpoint cross-origin to its issuer is logged. This is the class of bug behind CVE-2025-6514.

Audit attribution

target_app and scope_used were written as null on every line. They are now resolved from the federated catalog for tools/call and from the URI scheme for resources/read; gateway marks a builtin. Without them, the audit trail of a federating gateway can only say which tool name was called.

Baseline scope

Per-tool scopes are the authorization model, but the builtins (whoami, list_cortex_resources, ...) require none by design — so without a floor, any valid token for this audience reaches them.

OAUTH_REQUIRED_SCOPES=mcp:access   # unset keeps the previous behaviour

Also

  • The linking callback no longer interpolates a provider-supplied error string into HTML unescaped.
  • X-Cortex-Backends is now documented, in the server instructions and inline, as a context-size optimization and not an access control: it narrows what tools/list shows, never what a token may call.

Upgrading

No breaking change with default configuration. Two things to check before deploying: a backend configured over remote http:// will now be dropped (switch it to https, or set CORTEX_ALLOW_INSECURE_BACKENDS=true deliberately), and CORTEX_TOOL_INTEGRITY_MODE defaults to warn — set it to block once you have seen a few refreshes come back clean.

Image: ghcr.io/wellknownmcp/cortex-gateway:v0.2.0