Securing the Model Context Protocol as an enterprise control plane
Once a language model can discover and invoke tools across an enterprise, the thing you have built is not an integration layer. It is a control plane with a non-deterministic caller — and it should be governed like one.
What this is. An authored reference architecture and threat model — research and technical writing, not a description of a delivered client engagement. No client, no engagement outcome and no deployment result is claimed anywhere on this page. Where a control is described, it is a design position I am prepared to defend, not a report of one I operated.
Currency. Written against MCP specification revision 2026-07-28, the OWASP Top 10 for LLM Applications 2026 edition, NIST SP 800-63-4, NIST CSF 2.0, CIS Controls v8.1 and SLSA v1.2, as of 8 August 2026. The MCP specification and the OWASP LLM identifiers both changed within the last twelve months, and both changes invalidate widely circulated guidance. Source discipline records what was checked, what was corrected and what could not be verified.
01 The two MCPs, and why they are the same problem
The acronym collision is not a nuisance to be disambiguated in a footnote. It is the argument.
A Model Context Protocol
An open protocol that lets an AI application connect to external tools, data and workflows over JSON-RPC 2.0, through a host, a client and one or more servers. It standardizes what used to be bespoke per-integration glue.
B Managed control plane
A centralized management authority that authenticates principals, evaluates policy, mints credentials, distributes configuration and drives change across downstream infrastructure, clusters, pipelines, cloud accounts and SaaS estates.
Deploy the first at enterprise scale and you have built the second. An MCP estate connected to a ticketing system, a cloud account, a source repository, a database and a deployment pipeline can open accounts, read secrets, change configuration, move money and ship code. That is the definition of a control plane, and it inherits the control plane's governing property:
What MCP adds to that inheritance is a caller that cannot be reasoned about deterministically. Traditional control-plane security assumes an authenticated human operator or a program whose behaviour is fixed at build time. Here the caller is a language model that composes its next action from whatever text has entered its context — including text supplied by an attacker through a support ticket, a web page or a tool description. The perimeter assumption that the client is on your side does not survive that.
1 Authority without a human in the loop
Agentic workflows exist precisely to remove the operator from each step. Every consent prompt you add is friction the deployment was built to eliminate, which is why consent fatigue is a security control failure and not a UX complaint.
2 Instructions and data share a channel
Retrieved content and tool metadata land in the same context window as the operator's intent. There is no reliable in-band delimiter between a request and a payload pretending to be one.
3 Composition amplifies
A host connected to five servers has not five attack surfaces but the cross product: content read from one server can drive a mutating call against another, and neither server can see the other half of the chain.
02 Reference architecture
Vendor-neutral, expressed as planes and boundaries rather than products. The rule that matters is that no tier inherently holds the authority of another.
03 Trust boundaries and what crosses them
A boundary you have not written down is a boundary you are not defending. For each, the question is what crosses, what could be forged, and what the blast radius is if it is.
| Boundary | Separates | What crosses | Primary abuse | Enforceable control |
|---|---|---|---|---|
| TB-1 | Model context ↔ enforcement plane | Tool schemas and descriptions inbound; structured tool calls outbound; retrieved resource content inbound. | Tool description injection; schema tampering; tool shadowing across servers; consent fatigue exploitation. | Server-scoped tool namespaces; schema pinning and diff-on-update; risk-tiered consent; reject duplicate registrations across connections. |
| TB-2 | Enforcement ↔ server execution | Authorized calls with an exchanged, audience-bound token; normalized results. | A compromised or malicious server escaping its runtime, or reusing a credential outside its intended context. | Per-server workload identity; audience-bound ephemeral tokens; sandboxed runtime with dropped capabilities and no ambient network. |
| TB-3 | Server ↔ managed system | API calls carrying the server's own downstream credential. | Confused deputy; over-scoped downstream role; SSRF into internal or metadata endpoints. | Least privilege enforced at the target, independently of the plane; destination allowlists; link-local and private-range egress denial. |
| TB-4 | Plane ↔ evidence and recovery | Audit events outbound; key operations requested, never key material returned. | Log deletion or poisoning to evade detection; backup destruction to prevent recovery; key extraction. | Append-only external archive under separate administration; non-exportable keys in a KMS/HSM boundary; backup credentials the plane does not hold. |
Three boundaries the four-way model does not number
The numbered boundaries are the ones a request crosses. These three are real boundaries that a request does not cross, which is exactly why they get forgotten.
A Server to server
When an MCP server calls a second MCP server, or fronts a third-party API, it is simultaneously a resource server to its caller and a client to its target. Those are two different identities carrying two different tokens. The specification is explicit that the token received from the client is not the token to send onward.
B Registry to runtime
The path by which a server definition becomes a running process is a supply chain, and it is usually the least governed part of the estate. A curated catalogue with signature verification and digest pinning is the difference between installing software and executing whatever a repository happened to contain this morning.
C Management plane to policy
Whoever can author policy can widen it. There is no network boundary to place here — the control is separation of duties, four-eyes review on dangerous rules, and policy history in version control that the plane cannot rewrite. Treated in §10.
04 Threat taxonomy
Three tiers, because they need three different kinds of answer. Tier 1 is inherent to the protocol and its ecosystem. Tier 2 arises from putting a language model in the decision path. Tier 3 is ordinary control-plane security that people skip because the deployment feels experimental.
| Threat | Framework anchor | Mechanism | Control that actually holds |
|---|---|---|---|
| Tool poisoning & description injection | LLM01:2026 LLM08:2026 | The model reads tool names, descriptions and parameter schemas to plan. A server that controls those fields can place adversarial instructions in them, which the model may treat as authoritative. | Treat tool metadata as code: review it, pin it, hash it, and diff schemas on every update with re-approval on change. Content filtering helps and does not suffice. |
| Tool shadowing across servers | LLM03:2026 | Two connected servers expose the same tool name in a flat namespace. The model selects the wrong one, and a trusted operation is served by an untrusted provider. | Server-scoped names as a hard requirement, not a display convention. Reject duplicate registrations across connections. The spec notes the server name from serverInfo is not guaranteed to be unique across servers and SHOULD NOT be relied upon for disambiguation. |
| Rug pull — silent redefinition | LLM04:2026 | A server behaves correctly through review and adoption, then changes tool behaviour or descriptions after trust is established. | Digest pinning rather than tag or version pinning; schema and description diffing on update; approval required for any scope or capability expansion. |
| Confused deputy via proxy servers | API5:2023 LLM03:2026 | A proxy server holds a static client identifier at a third-party authorization server while letting MCP clients register dynamically. An existing consent cookie can then be exploited to obtain authorization codes without fresh user consent. | Per-client consent stored server-side and checked before the third-party flow begins; consent cookie set only after approval; CSRF protection and frame-ancestors on the consent page. |
| Token passthrough & audience confusion | API2:2023 | The host forwards the user's own access token to a server, which forwards it downstream. Audience validation is broken, rate limiting and monitoring keyed to audience are bypassed, and the downstream log shows the wrong actor. | Exchange, never forward. The current specification forbids passthrough outright — see §06 for the exact normative text. |
| State handle hijacking | API1:2023 | MCP is stateless; servers that need continuity mint an explicit handle returned as an ordinary tool argument. An attacker who obtains or guesses a handle operates on another user's state. | Never treat handle possession as authentication. Bind handles server-side to the authenticated principal — key stored state by user identity derived from the verified token, not from anything the client supplies. |
| Capability misrepresentation | No spec control | A server declares capabilities without cryptographic attestation. Nothing in the protocol proves a server is what it claims to be beyond the transport's identity. | Compensate outside the protocol: a signed catalogue, an operator-maintained registry, and admission control that refuses anything not in it. This is a genuine gap, not a solved problem. |
| Indirect prompt injection | LLM01:2026 | Adversarial instructions embedded in content the model retrieves — a ticket, an email, a page, a document — contaminate the context and drive unauthorized mutating calls against other connected servers. | Assume it succeeds. Constrain what a successful injection can reach: least privilege per tool, structural policy gates on mutating calls, egress control, and approval binding for destructive actions. See §05. |
| Consent fatigue exploitation | LLM03:2026 | High-frequency approval prompts train operators to approve reflexively. The destructive request arrives looking like the ninety before it. | Risk-tiered consent so that the prompts that remain are rare and meaningful, and structured diffs rather than raw payloads so that what is being approved is legible in the two seconds anyone will spend on it. |
| Exfiltration through legitimate calls | LLM02:2026 | No exploit required. The model is persuaded to read sensitive data with one authorized tool and write it out with another — a webhook, an email draft, a file write, a search query. | Separate read scope from write-and-send scope in policy, not in convention. Destination allowlists on anything that leaves. Output inspection on the egress path. |
| Hidden context exposure | LLM08:2026 | System instructions, retrieved policy text and tool schemas are extracted or reconstructed, revealing internal structure, allowlists and control logic. | Assume the prompt is public. Put no secret, no credential and no security-relevant decision in it — if disclosure of the system prompt breaks a control, the control was in the wrong place. |
| Unbounded consumption | LLM06:2026 API4:2023 | A loop of tool calls, an oversized resource read, or a recursive agent chain consumes capacity and cost without a natural stopping condition. | Iteration limits on tool loops, payload size caps, per-principal rate limits and a cost budget that terminates rather than alerts. |
| Improper output handling | LLM10:2026 | Model output is passed into a shell, a SQL string, a template or a browser without treating it as untrusted input. | Parameterized invocation everywhere. Model output is user input from an unauthenticated source and should be handled with exactly that suspicion. |
| Command injection in host or server | API8:2023 | Ordinary unsafe shell interpolation — a URL, a filename or a parameter concatenated into a command line. A rogue server returns a crafted value and obtains code execution on the workstation. | No shell interpreter in the invocation path. Parameterized process spawning with array arguments; scheme and character allowlists on anything that reaches a command. |
| SSRF & metadata exfiltration | API7:2023 | A fetch-style tool is pointed at link-local or internal addresses — classically the cloud instance metadata endpoint — and the credentials it returns enter the model context and then the logs. | Network-level egress filtering that denies link-local and private ranges; DNS resolution validated after redirect, not only before; destination allowlists on every outbound fetch. |
| Local server compromise | LLM04:2026 | A stdio server runs as a child process with the user's own privileges and reaches the whole home directory, including cloud and SSH credentials. | Containerized or kernel-isolated execution, non-root, read-only root filesystem, dropped capabilities, explicit and minimal mounts. See §09. |
| Supply-chain substitution | LLM04:2026 | Typosquatted or malicious server packages in public registries; unsigned artifacts; dependency compromise reaching the runtime. | Curated catalogue, signature and provenance verification at admission, digest pinning, SBOM generation and continuous component scanning. |
| Credential leakage at rest | LLM02:2026 | API keys and tokens in configuration files, environment files, container layers, support bundles and traces. | Managed secret stores and short-lived credentials; redaction enforced at the serialization layer rather than by reviewer discipline; secret scanning across source, build logs, images and support artifacts. |
| Unauthenticated management exposure | API8:2023 API9:2023 | A broker, registry or server bound to all interfaces, started in a development mode, or reachable from the internet without authentication — the failure mode that produced internet-wide exposure for earlier orchestration platforms. | Localhost binding by default; Origin validation; authenticated private access paths; an authoritative exposure inventory checked continuously by external scanning. |
| Audit suppression | ATT&CK Defense Evasion | Logs disabled, deleted or drowned. The most efficient move available to an attacker who already holds administrative access to the plane. | Continuous export to an archive under separate administration; alert on telemetry volume collapse and on export errors, not only on malicious events. |
05 The untrusted caller
Indirect prompt injection is the threat that makes MCP security different from API security. It deserves to be modelled as a path, with named gates, so that the honest question can be asked at each: is this a control, or is it a hope?
What follows from taking that seriously
- Read scope and write scope belong to different tokens. If one exchanged credential can both read the ticket and post the webhook, the injection has everything it needs. Split them and the chain requires two independent authorizations.
- Mutating tools should be structurally constrained, not free-form. A tool that accepts a SQL string accepts an instruction; a tool that accepts a table name, a bounded filter and a row limit accepts a request. Schema design is a security control and it is usually the cheapest one available.
- Approval must bind to the exact payload. An operator who approved a diff should not have approved whatever executes next. Bind consent cryptographically to a hash of the concrete request, with a short freshness window, so approval cannot be transplanted.
- Cross-server chains are the unit of analysis. Threat-model the pairs, not the servers. “Read from the ticketing server, write to the repository server” is the risk; neither server can see it alone.
- Human-in-the-loop is a control only where a human can actually adjudicate. The specification says there should always be a human able to deny tool invocations. That is right, and it is also the control most eroded by volume — which is why tiering it matters more than mandating it.
06 What the specification now requires
MCP historically prescribed no authentication and no authorization model, which is why so much published guidance treats identity as entirely the implementer's problem. That is out of date. Revision 2026-07-28 carries a normative authorization specification, and several of its requirements are the exact controls this architecture argues for.
| Requirement | Normative text | Architectural consequence |
|---|---|---|
| No token passthrough | “MCP servers MUST NOT accept any tokens that were not explicitly issued for the MCP server.” And on the client side: “MCP clients MUST NOT send tokens to the MCP server other than ones issued by the MCP server's authorization server. MCP servers MUST only accept tokens that are valid for use with their own resources. MCP servers MUST NOT accept or transit any other tokens.” | The zero-passthrough principle is no longer a hardening recommendation you have to argue for. It is a conformance requirement, and an implementation that forwards the user's token is non-conformant as well as unsafe. |
| Audience validation | “MCP servers MUST validate that access tokens were issued specifically for them as the intended audience, according to RFC 8707 Section 2.… Invalid or expired tokens MUST receive a HTTP 401 response.” | Audience binding moves from a design preference to a testable assertion. Write the negative test: present a token minted for a different server and require a 401. |
| Resource indicators | “MCP clients MUST implement Resource Indicators for OAuth 2.0 as defined in RFC 8707… The resource parameter… MUST be included in both authorization requests and token requests… MUST use the canonical URI of the MCP server.” And: “MCP clients MUST send this parameter regardless of whether authorization servers support it.” |
Down-scoping is expressed at request time, not inferred afterwards. The last clause matters operationally — the client sends it even against an authorization server that ignores it, so the estate is ready when the server catches up. |
| Protected resource metadata | “MCP servers MUST implement OAuth 2.0 Protected Resource Metadata (RFC 9728). MCP clients MUST use OAuth 2.0 Protected Resource Metadata for authorization server discovery.” | Discovery is standardized, which removes a class of configuration error and gives the broker a machine-readable place to publish required scopes. |
| PKCE, verified | “MCP clients MUST implement PKCE according to OAuth 2.1 Section 7.5.2 and MUST verify PKCE support before proceeding with authorization… If code_challenge_methods_supported is absent, the authorization server does not support PKCE and MCP clients MUST refuse to proceed.” |
Refusing to proceed is the unusual and correct part. Most implementations degrade silently when a capability is missing; here the required behaviour is to stop. |
| Per-client consent | “MCP proxy servers using static client IDs MUST obtain user consent for each dynamically registered client before forwarding to third-party authorization servers.” And: the consent cookie “MUST NOT be set until after the user has approved the consent screen.” | This is the confused-deputy fix stated as a requirement. The ordering clause is the subtle half — setting the cookie first renders the consent screen decorative. |
| State handles are not credentials | “MCP servers MUST NOT treat possession of a state handle as authentication… SHOULD bind handles server-side to the authenticated user… where the user ID is derived from the verified token rather than supplied by the client.” | Object-level authorization on every call. This is API1:2023 in MCP clothing, and stateless protocols make it easier to get wrong. |
| Origin validation | “Servers MUST validate the Origin header on all incoming connections to prevent DNS rebinding attacks… When running locally, servers SHOULD bind only to localhost (127.0.0.1) rather than all network interfaces (0.0.0.0).” |
The default-exposure failure that has burned every previous developer-tool ecosystem is addressed directly. Verify it rather than assume the SDK does it. |
| Server as onward client | “If the MCP server makes requests to upstream APIs, it may act as an OAuth client to them. The access token used at the upstream API is a separate token, issued by the upstream authorization server. The MCP server MUST NOT pass through the token it received from the MCP client.” | The two-identity rule, made explicit. This is the requirement most often violated by servers written as thin proxies. |
draft-ietf-oauth-v2-1, revision 15 as of March 2026, no RFC number). Building against it is reasonable and current practice; describing it as a published standard is not, and the distinction matters in a control narrative an auditor will read.07 Delegated identity without passthrough
The single highest-value control in the architecture, because it bounds a class of compromise: a server that is fully compromised holds a credential no other MCP server will accept, so its blast radius collapses to its own downstream scope rather than the user's whole session.
| Dimension | Direct passthrough | Exchanged, audience-bound token |
|---|---|---|
| Audience | Broad — whatever the user's token was issued for, usually an entire API surface. | One target — the canonical URI of the specific server, rejected by every other resource server. |
| Lateral movement | Free — one compromised server reaches everything the user can reach. | Structurally blocked — not detected and stopped, but never accepted in the first place. |
| Permission breadth | The user's full role, regardless of what the call needed. | The scope of this call, requested explicitly at exchange time. |
| Lifetime | Session-length — hours, and often renewable. | Minutes or less, cached only within its own validity. |
| Attribution | The downstream log shows the user, with nothing recording which component acted. | A delegation chain — the act claim names the acting party alongside the subject. |
| Revocation | All or nothing — revoking reaches the user's whole session. | Granular — stop minting for one audience without disturbing anything else. |
| Rate limiting & monitoring | Bypassed where controls key on audience or client identity. | Enforceable, because the identity presented is the one the control was designed around. |
Delegation, not impersonation
RFC 8693 distinguishes the two precisely, and the distinction is the whole audit story. Under impersonation the acting party becomes indistinguishable from the subject; under delegation it keeps its own identity and the token carries both. The act claim is what expresses delegation. Be careful how far you push that, though: the RFC leaves the token representation of impersonation to the authorization server's discretion and policy, so the absence of act is a strong convention rather than a test a verifier is entitled to rely on. If the distinction matters to a downstream control, require the claim explicitly rather than inferring it from a gap.
“The
act(actor) claim provides a means within a JWT to express that delegation has occurred and identify the acting party to whom authority has been delegated.”“For the purpose of applying access control policy, the consumer of a token MUST only consider the token's top-level claims and the party identified as the current actor by the
RFC 8693, OAuth 2.0 Token Exchange, §4.1 — Proposed Standard, January 2020actclaim.”
POST /oauth/token HTTP/1.1
Host: sts.example.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic <host client credentials>
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchange
&subject_token=<the user's token — consumed here, never forwarded>
&subject_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aaccess_token
&resource=https%3A%2F%2Fmcp.example.com%2Fissue-service
&scope=mcp%3Atools%3Aexecute+issues%3Aread
&requested_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aaccess_token
audience parameter is optional, so an authorization server is not obliged to honour it — which is exactly why MCP additionally mandates the RFC 8707 resource parameter and requires the client to send it whether or not the server supports it. And nested act claims record a delegation chain's history but are informational: authorization decisions consider the current actor only.Verification at the resource server
Signature validity is not authorization. The Storm-0558 investigation turned on precisely this: libraries verified signatures cryptographically but did not automatically perform issuer and key-scope validation, and callers assumed they had. A conforming validator checks all of it — issuer, audience, scope, lifetime, key scope and the presence of the expected delegation claim — and returns 401 for an invalid or expired token, 403 for insufficient scope with a WWW-Authenticate challenge naming the scopes actually required.
08 The deterministic policy gate
Between a model that decided to do something and a system that would do it, there should be a component whose behaviour does not depend on what the model was told. This is the gate that holds when everything upstream has been fooled.
The rule shape
Default deny, an allow that requires both an empty violation set and an affirmative authorization rule, and violations aggregated from independent families so that adding a new class of check cannot accidentally weaken an existing one. Expressed in Rego:
package mcp.tools.authz
# On OPA 1.0 and later, Rego v1 semantics are the default and
# `import rego.v1` is a no-op. It is retained only by libraries
# that must also parse under pre-1.0 runtimes.
default allow := false
allow if {
count(violations) == 0
is_action_authorized
}
violations contains r if { some r in structural_violations }
violations contains r if { some r in destructive_violations }
violations contains r if { some r in classification_violations }
violations contains r if { some r in approval_violations }
violations contains r if { some r in environment_violations }
# Every family needs at least one rule head, or the module does not
# compile — an undefined family is an unsafe variable, not an empty
# set. One placeholder each; replace the bodies with the real checks.
structural_violations contains "Operation was not parsed into a typed structure." if {
not input.operation.parsed
}
destructive_violations contains "Mutation submitted without a bounded predicate." if {
input.operation.kind == "mutate"
not input.operation.predicate
}
classification_violations contains "Restricted data touched without a data-owner role." if {
input.target.classification == "restricted"
not "data_owner" in input.principal.roles
}
environment_violations contains "Production change outside an approved window." if {
input.target.environment == "production"
not input.change.window_open
}
# Affirmative rules are separate and additive. A read in a
# non-production environment by a recognized role is allowed;
# the same read in production additionally requires assurance;
# a mutation additionally requires a bound approval.
is_action_authorized if {
input.operation.kind == "read"
input.target.environment in {"development", "staging", "qa"}
some role in input.principal.roles
role in {"analyst", "developer", "admin"}
}
is_action_authorized if {
input.operation.kind == "read"
input.target.environment == "production"
input.principal.assurance == "phishing_resistant"
some role in input.principal.roles
role in {"admin", "data_owner"}
}
is_action_authorized if {
input.operation.kind == "mutate"
some role in input.principal.roles
role in {"admin", "data_owner"}
approval_is_bound
}
# Approval is bound to the exact payload and is short-lived, so an
# approval obtained for one request cannot authorize another. Note that
# the current time arrives in the input document rather than being read
# from the clock inside the policy: a rule that calls time.now_ns() is
# not replayable from its logged input, which forfeits the reproducibility
# this gate exists to provide.
approval_is_bound if {
input.approval.verified == true
input.approval.payload_hash == crypto.sha256(input.operation.canonical)
age_ns := input.context.now_ns - (input.approval.issued_at * 1000000000)
age_ns >= 0
age_ns <= 300 * 1000000000
endswith(input.approval.approver, "@example.com")
}
approval_violations contains "Mutating operations require a verified approval." if {
input.operation.kind == "mutate"
not input.approval.verified
}
approval_violations contains "Approval hash does not match the submitted payload." if {
input.operation.kind == "mutate"
input.approval.verified == true
input.approval.payload_hash != crypto.sha256(input.operation.canonical)
}
# Without this rule an expired approval denies with an empty violation
# set: the caller learns only that it was refused, not why. Every path
# that can deny needs a reason, or the deny is undiagnosable in
# production and untestable in review.
approval_violations contains "Approval is outside its freshness window." if {
input.operation.kind == "mutate"
input.approval.verified == true
input.context.now_ns - (input.approval.issued_at * 1000000000) > 300 * 1000000000
}
DROP, check whether WHERE appears, count semicolons. That is not structural evaluation, and it is bypassable by anyone who has read the policy: comments, string literals, unicode, nested quoting, dialect-specific syntax and casing tricks all defeat substring matching. If the gate is going to make a structural claim, the enforcement point must parse the operation into an abstract syntax tree and put the parsed structure into the input document — statement type, referenced objects, predicate presence, projected columns — so the policy evaluates a typed object rather than a string. A policy that greps is a speed bump described as a wall.What the input document must carry, and what it must not
Principal
Identity, roles, authentication assurance, elevation state and its expiry. Not a display name, and never a token.
Workload
Which server and which adapter version originated the call, and under which attested workload identity.
Operation
The parsed operation — kind, targets, predicates, bounds — plus a canonical serialization used for hashing. Not the raw string alone.
Target
Tenant, environment, data classification and the sensitivity of what is touched. This is where an object-level authorization decision becomes possible.
Approval
Verified flag, approver identity, issue time and a hash bound to the canonical payload. Time-bounded, single-use, non-transferable.
Correlation
Session, conversation and request identifiers, so that the decision, the execution and the downstream effect can be joined afterwards.
09 Execution isolation
Assume the server is hostile. Not because most are, but because the cost of that assumption is a container configuration and the cost of the alternative is the workstation.
A local server launched over stdio is a child process of the host application and inherits the invoking user's privileges — the home directory, the cloud credential files, the SSH keys, the browser profile. Compromise it through a poisoned dependency or a prompt-driven misuse and the attacker has everything the user has. Standard container runtimes reduce that but share the host kernel, so a kernel-level escape remains on the table. A userspace application kernel interposes: the sandboxed workload's system calls are handled by a kernel implemented in userspace rather than passed to the host.
| Control | What it prevents | How it is verified — the negative test |
|---|---|---|
| Kernel isolation | A container escape reaching the host kernel from an untrusted server. | Query the kernel from inside the sandbox and confirm it reports the sandbox kernel, not the host's. |
| No ambient network | Exfiltration, callback channels, and SSRF originating in the server itself. | Attempt an outbound connection from inside and require it to fail. Grant egress only through the broker, per destination. |
| Read-only root filesystem | Persistence, binary replacement, and tampering with the server's own code. | Attempt a write outside the designated scratch mount and require a read-only filesystem error. |
| Non-root execution | Privileged operations inside the sandbox; damage from a partial escape. | Assert the effective UID is the unprivileged service account, and that no-new-privileges is set. |
| All capabilities dropped | Raw sockets, mount operations, module loading, ptrace against other processes. | Enumerate capabilities inside the sandbox and require an empty set. |
| Non-executable scratch space | Dropping and running a payload in the one writable location. | Write a binary to the scratch mount, attempt execution, require permission denied. |
| Explicit, minimal mounts | Access to home directories, credential files and adjacent projects. | Attempt to read a canary file placed outside the mounted scope and require failure. Mount read-only wherever the tool does not write. |
| Resource bounds | Denial of service against the host from a runaway or deliberately abusive server. | Memory, CPU and process-count limits set explicitly and exercised under load, not left at defaults. |
| Build-tool stripping | Post-compromise tooling — package managers and compilers — available inside the runtime image. | Multi-stage build; assert the package manager binaries are absent from the final image. |
Server-side input handling
Isolation bounds the damage; input validation prevents most of it from starting. Three requirements carry disproportionate weight in an MCP server, because they are the three that a model-driven caller will reach accidentally as well as maliciously:
- Path containment resolved, not inspected. Rejecting
..in a string is not containment. Resolve the candidate path fully — through symlinks — and then assert that the resolved result is still inside the permitted root. A canonicalization step that falls back to the original path when resolution fails is a real, exploited bug class, not a hypothetical one. - Bounded payloads. Size caps on reads and writes, row limits on queries, and iteration limits on tool loops. Absent these, a single tool call is a denial-of-service primitive and a cost incident.
- Typed schemas over free text. Constrain parameters to enumerations, patterns and ranges wherever the tool's purpose allows. Every free-form string field is a place where an instruction can be smuggled to something downstream that parses it.
11 Incident register
Six compromises — five with nothing to do with AI, all of them directly instructive. They are here because the failure pattern is the one an MCP estate will reproduce.
| Incident | What happened | What it implies for an MCP estate |
|---|---|---|
| Storm-0558 2023, updated 2024 |
An acquired Microsoft consumer signing key was used to forge tokens that reached enterprise email. Microsoft's stated leading hypothesis remained that “operational errors resulted in key material leaving the secure token signing environment,” later accessed through a compromised engineering account with access to a debugging environment. Separately, Microsoft found that validation libraries verified signatures but had not automatically performed the necessary issuer and key-scope validation. | Cryptographic validity is not authorization. Validate issuer, audience, scope, purpose and lifetime — not just the signature. Keep signing material non-exportable and forbid sensitive diagnostic artifacts from leaving a protected environment. Both halves of this apply directly to a broker minting delegated tokens. |
| CircleCI December 2022 – January 2023 |
Malware on an engineer's laptop stole “a valid, 2FA-backed SSO session,” which the attacker used to impersonate the employee and escalate into production, exfiltrating customer environment variables, tokens and keys. Encryption at rest did not protect the data: the attacker “extracted encryption keys from a running process.” | Multi-factor authentication does not survive session theft, and encryption at rest does not defend against an authorized running process. Both are lessons for a broker that holds delegated credentials in memory. The remediation direction — toward OIDC, granular permissions and more ephemeral credentials — is the same direction this architecture argues for. |
| Okta support system October – November 2023 |
Files associated with 134 customers were accessed; some were HAR files containing session tokens, and the sessions of five customers were hijacked. The root cause was a service-account credential saved into an employee's personal Google profile. A roughly 14-day investigative gap arose because navigating directly to a different interface generated an entirely different log event than the one being monitored. | Telemetry completeness must be validated by adversary path, not by volume. A monitored event type is not a monitored capability. Sanitize support artifacts — diagnostic bundles from an AI tool chain are exactly the kind of artifact that quietly contains tokens. |
| TeamCity CVE-2026-63077 Actively exploited, August 2026 |
An unauthenticated attacker with HTTP(S) access can exploit the agent-polling protocol through unsafe deserialization to execute operating-system commands with the privileges of the server process. CVSS 9.8, CWE-502. Fixed in 2025.11.7 and 2026.1.3, with a patch plugin for older supported installations. JetBrains reported active and attempted exploitation, and it was added to CISA's Known Exploited Vulnerabilities catalogue on 5 August 2026. | An agent-polling protocol is a fleet-wide trust path and must be fuzzed before it becomes one. This is the closest structural analogue to an MCP transport in production today: an externally reachable orchestration service whose deserialization boundary is the whole attack. Note also the compensating control — restricting network reach — is necessary and is not a substitute for patching. |
| ingress-nginx CVE-2025-1974 March 2025 |
CVSS 9.8. “An unauthenticated attacker with access to the pod network can achieve arbitrary code execution in the context of the ingress-nginx controller. This can lead to disclosure of Secrets accessible to the controller.” Kubernetes noted that “in the default installation, the controller can access all Secrets cluster-wide.” Fixed in 1.11.5 and 1.12.1. | Internal networks are trust boundaries too, and a component's default privilege is usually the real vulnerability. Ask what an MCP server can read if it is fully compromised — and if the answer is “every secret in the namespace,” the code-execution flaw was only the delivery mechanism. |
| Cursor IDE, CVE-2026-50548 / 50549 June 2026 |
Two sandbox-escape remote code execution flaws in Cursor IDE, both CVSS 9.8, fixed in version 3.0. One allows agent manipulation of a working-directory parameter so the sandbox grants write access outside the workspace; the other is a canonicalization failure where a fallback to the original path allows a write without approval. The discovering researchers note the injection can be delivered through a malicious MCP server request or a poisoned web result. | The sandbox is part of the trust boundary and it can have its own bugs. This is the AI-adjacent case in the register, and the honest reading is narrow: these are editor sandbox-escape flaws, not protocol flaws. The transferable lesson is the canonicalization fallback — resolve, then assert containment, and fail closed when resolution fails. |
12 Standards crosswalk
An architectural mapping, not an official equivalency. A control that satisfies one framework should never be assumed to satisfy another — the point of the table is to make the evidence conversation tractable, not to claim conformity.
| Control domain | NIST CSF 2.0 | ISO/IEC 27001 & 27002 | CIS Controls v8.1 | AI-specific anchor |
|---|---|---|---|---|
| Governance & risk ownership | Govern | ISMS context, leadership, planning, risk treatment | Governance across safeguards; Control 17 | NIST AI RMF GOVERN 1.2 — trustworthy-AI characteristics integrated into policy and practice |
| Estate inventory | Identify | Asset and information management | Controls 1–2; data inventory under Control 3 | A signed catalogue of approved servers, with owners |
| Identity & account lifecycle | Protect | Identity and access management | Control 5 — Account Management | Per-server workload identity, not shared secrets |
| Authorization, PAM & JIT | Protect | Access control; segregation of duties | Control 6 — Access Control Management | OWASP LLM LLM03:2026 Excessive Agency |
| Secrets & key protection | Protect | Cryptography; information protection | Control 3 — Data Protection | OWASP LLM LLM02:2026 Sensitive Information Disclosure |
| Network isolation & egress | Protect | Network security controls | Control 12 — Network Infrastructure Management | OWASP API API7:2023 SSRF |
| Vulnerability management | Identify / Protect | Technical vulnerability management | Control 7 — Continuous Vulnerability Management | Known-exploited catalogue as an emergency trigger |
| Audit & telemetry | Detect | Logging and monitoring | Control 8 — Audit Log Management | Tool-call traces with caller identity, arguments and downstream effect |
| Secure software lifecycle | Protect | Secure development, change and supplier controls | Control 16 — Application Software Security | SLSA v1.2 build and source tracks; OWASP LLM LLM04:2026 Supply Chain |
| Incident response | Respond | Incident planning, assessment and response | Control 17 — Incident Response Management | NIST AI RMF MANAGE 2.4 — mechanisms to supersede, disengage or deactivate |
| Backup & recovery | Recover | ICT readiness and continuity | Data-recovery safeguards | Recovery that does not depend on the plane |
| Supplier & connector risk | Govern / Identify | Supplier relationships; cloud security | Service-provider and supply-chain safeguards | CSA AI Controls Matrix v1.1 — secure development lifecycle for AI applications |
Regulatory scope follows what the estate touches
Obligations attach to the systems an MCP deployment can reach, not to the deployment's own novelty. Three worth naming precisely:
- GDPR Article 32 requires risk-appropriate technical and organizational measures, and names four elements explicitly: pseudonymisation and encryption; the ability to ensure ongoing confidentiality, integrity, availability and resilience; the ability to restore availability and access in a timely manner after an incident; and a process for regularly testing, assessing and evaluating the effectiveness of those measures. The fourth is the one architecture documents usually omit and auditors always ask about.
- HIPAA technical safeguards at 45 CFR §164.312 — access control, audit controls, integrity, person or entity authentication, and transmission security — map cleanly onto the controls above. HHS published a proposed rule in January 2025 to strengthen the Security Rule; as of publication it is neither finalized nor withdrawn, and the existing Security Rule remains in effect. Design to the rule that is in force and track the proposal separately.
- SOC 2 and ISO/IEC 27001 treat these components as in-scope systems once they can affect a system in scope. An MCP server that can change a production configuration is a production system, whatever the internal project classification says.
13 Assurance and testing
Different techniques find different defect classes. They are layers, not competing options, and an annual penetration test is not a testing programme.
| Layer | What it must cover here specifically | Cadence |
|---|---|---|
| Static analysis | Unsafe deserialization, shell construction, path handling and canonicalization fallbacks, SSRF sinks, authorization-bypass patterns, secret handling. | Every change |
| Composition analysis | Server dependencies, base images, plugins and SDKs, with an SBOM per artifact and continuous re-evaluation as new advisories land. | Every build, plus continuous |
| Configuration scanning | Public administrative endpoints, permissive bindings, missing Origin validation, over-scoped downstream roles, absent audit configuration, unencrypted stores. | Every infrastructure change |
| Secret scanning | Source, build logs, container layers, artifacts and support bundles — and the model's own transcript and trace stores, which are a new and frequently unscanned location. | Commit, build, release |
| Dynamic and API testing | Authentication bypass, object- and function-level authorization, audience validation against a foreign token, request limits, SSRF, rate controls. | Continuous in staging |
| Fuzzing | JSON-RPC parsing, transport framing, schema validation and the policy evaluator's edge cases. Fuzz any agent or webhook protocol before it becomes a fleet-wide trust path. | Campaign based |
| Authorization property tests | Generated across the role, tenant and environment matrix, asserting invariants rather than checking examples. | Every policy or API change |
| Adversarial prompt testing | Injection through every ingestion path the estate actually has — tickets, documents, pages, tool descriptions — measured on whether the deterministic gates held, not on whether the model was fooled. | Per release, and on new server onboarding |
| Penetration testing | Session theft, authorization-boundary crossing, tenant escape, policy manipulation, key access, agent impersonation, malicious server registration, artifact substitution, audit suppression, backup destruction. | Major changes, plus periodic |
| Red team | Start from a realistic foothold — a compromised workstation, a stolen session, a poisoned dependency, a malicious server — and measure whether it can be turned into durable estate-wide authority. | Periodic |
| Fail-safe testing | Loss of the identity provider, the policy engine, the key service, the audit sink and each connector, verifying the system degrades closed and the degradation is visible. | Pre-production, plus periodic |
| Recovery testing | Corrupted desired state and a compromised administrator, not merely a crashed host. Restore from evidence whose integrity does not depend on the plane. | Scheduled game days |
14 Metrics that mean something
Measure enforcement and exposure, not activity. “Servers reviewed” and “people trained” are weak outcome indicators if administrators still hold reusable global tokens and one endpoint is public.
| Indicator | Definition | Reference target |
|---|---|---|
| Token audience isolation | Servers that reject a token minted for a different audience, over total servers. Measured by test, not by configuration review. | 100% |
| Passthrough incidence | Requests in which an inbound token was forwarded unchanged to any downstream system. | 0 |
| Unique server identity coverage | Servers holding a unique, scoped workload identity, over total servers. | 100% |
| Standing privilege rate | Administrators with non-expiring production authority over the plane, over total administrators. | Approaching 0% |
| Phishing-resistant coverage | Privileged interactive identities using a compliant strong authenticator, over total privileged identities. | 100% |
| Unapproved public endpoints | Management, registry or server endpoints reachable externally without an approved exception. | 0 |
| Cross-tenant escape tests | Forbidden cross-tenant operations that succeeded in the automated negative suite. | 0 |
| Catalogue coverage | Running servers present in the signed catalogue with a pinned digest, over total running servers. | 100% |
| Provenance at admission | Production deployments whose artifact signature and provenance were verified before execution. | 100% |
| Exploited-vulnerability exposure time | From publication of a known-exploited issue affecting a component of the plane, to effective mitigation. | Emergency SLO, hours not weeks |
| Audit completeness | Expected high-value events successfully received at the external archive, over expected events. | Approaching 100% |
| Audit export error rate | Failed security-event exports over total. A rise here is an incident indicator in its own right. | Near zero, alert immediately |
| Approval binding rate | Mutating operations executed under an approval cryptographically bound to the exact payload, over all mutating operations. | 100% |
| Approval grant rate | Approvals granted over approvals requested, tracked as a consent-fatigue indicator. A rate approaching one means the prompt has stopped functioning as a decision. | Monitored, not maximized |
| Denied-then-succeeded sequences | Cases where a repeatedly denied operation subsequently succeeded — the signature of an attacker or an agent iterating toward a permitted phrasing. | Investigated, every one |
| Credential revocation completion | From revocation initiation to every enforcement point rejecting the credential. | Bounded and exercised |
| Demonstrated recovery | Measured clean-room restoration against the approved objective. | Meets the objective, proven |
15 Phased roadmap
Sequenced so that each phase is independently valuable and each gate is a thing that can fail. A phase whose exit criterion cannot fail is not a gate.
Phase 0 — Establish scope and stop the bleeding
Premise: most organizations already have an MCP estate; it simply has not been inventoried. Start by finding out what can already reach what.
Gate: a named owner for every server; zero unapproved external exposure; no code path that forwards an inbound token.
Phase 1 — Isolation and identity baseline
Gate: the cross-audience test — a token minted for one server is rejected by every other. A negative test proving a container cannot reach the network, write outside scratch, or read a canary outside its mounts. Audit events observable in the archive with production administration unable to delete them.
Phase 2 — Policy, supply chain and approval
Gate: an unsigned artifact is rejected and the rejection is logged; the negative authorization suite passes across the full role and tenant matrix; an approval issued for one payload demonstrably fails to authorize a different one.
Phase 3 — Continuous assurance and recovery
Gate: a completed restoration exercise, a red-team report showing the foothold could not be converted to durable estate-wide authority, and a fail-safe test per security dependency.
16 Decisions and open questions
Recorded with the reasoning intact, including the ones that are genuinely unresolved. An architecture document that contains no open questions is describing a system nobody has thought hard about.
| # | Decision | Reasoning | Status & revisit |
|---|---|---|---|
| D-01 | Treat the model as an untrusted caller holding a legitimate credential | It is the only assumption that survives indirect prompt injection. Every control is then placed to be effective whether or not the model was manipulated, which is a testable design property rather than a hope. | Settled · foundational |
| D-02 | Zero token passthrough, without exception | Converts full server compromise from lateral movement into a contained event. Now also a specification requirement, so the argument is no longer about whether but about migration order. | Settled · conformance |
| D-03 | Policy evaluates structure, never intent | A gate that reasons about what the request appears to mean inherits the ambiguity it exists to remove. Structural evaluation is reproducible, testable and explainable to an auditor; semantic evaluation is none of the three. | Settled · foundational |
| D-04 | Content filtering is defence in depth, never a control | Classifiers on adversarial natural language have no reliability guarantee. Budget them as rate reduction and never let a safety case rest on one. | Settled · annual |
| D-05 | Fail closed on loss of the policy or identity path | Authorization uncertainty must never silently become a permit. The availability cost is real and is accepted explicitly by the risk owner rather than absorbed as an implementation detail. | Settled · risk-owner approval |
| D-06 | Kernel-level isolation for third-party servers; container isolation for reviewed internal ones | Tiering by provenance rather than applying one posture everywhere. A uniform strict posture gets relaxed to the weakest requirement; a uniform weak one is indefensible for unreviewed code. | Settled, cost-sensitive · per onboarding |
| D-07 | Audit custody sits outside the plane's administrative domain | The team operating the estate must not be able to alter the evidence used to judge whether it operated safely. This also survives the compromise case, which internal logging does not. | Settled · governance |
| D-08 | Approval binds cryptographically to the canonical payload, with a short freshness window | Otherwise approval is transferable and an operator who approved one thing has approved the next thing. Freshness bounds the window in which a captured approval is useful. | Settled · foundational |
| D-09 | Digest pinning rather than version pinning for servers | A version tag is mutable in most registries. The rug-pull threat is specifically a change behind a stable identifier, which is exactly what a tag is. | Settled · stable |
| D-10 | No exactly-once or fully-mitigated claim anywhere in the architecture | Injection is not solved, capability attestation does not exist in the protocol, and content filtering is probabilistic. Stating residual risk plainly is what makes the rest of the document credible. | Settled · foundational |
Open questions — genuinely unresolved
Q1 Capability attestation
Nothing in the protocol lets a client cryptographically verify that a server is what it claims to be, or that its declared capabilities are honest. Signed catalogues compensate operationally but do not close it. Proposals exist — signed capability certificates, message-level authentication — and none is standardized.
Q2 Where the AST parser lives
Structural policy evaluation requires parsing the operation before the policy sees it. Putting a parser for every downstream query language in the enforcement point is a large surface with its own vulnerability profile. Pushing it to the server makes the parse untrusted. There is no clean answer; the current position is a small number of parsers for high-risk languages only, running sandboxed.
Q3 Consent at agentic speed
Risk-tiered consent reduces prompt volume but does not resolve the tension: the workflows with the most authority are exactly the ones designed to run without a human. Batch and budget-based approval models are promising and unproven at scale.
Q4 Cross-server chain authorization
Authorization is evaluated per call. The risk lives in sequences — read here, write there — and no widely deployed mechanism carries provenance from a read into the authorization decision for a later write. Taint tracking across tool calls is the obvious direction and nothing production-grade implements it.
Q5 Transcript and trace custody
Model transcripts, tool arguments and traces are a new class of sensitive store that inherits the sensitivity of everything the estate touched. Retention, access control and scanning for this class are immature almost everywhere, including in otherwise well-governed organizations.
Q6 Standards drift
The specification, the OWASP LLM identifiers, the OAuth 2.1 draft and the AI control frameworks all moved within the last twelve months. Any architecture in this space needs a scheduled re-verification cadence, and this one is written on the assumption that parts of it will be wrong within a year.
17 Source discipline
This reference was assembled from working drafts and then checked against primary sources. Several claims did not survive. Recording that is not a disclaimer — it is the part of the method that makes the rest usable.
| Claim as drafted | What the primary source actually says | Why it matters |
|---|---|---|
MCP specification revision 2025-06-18; transports are stdio and HTTP+SSE | The current revision is 2026-07-28. The transports are stdio and Streamable HTTP; HTTP+SSE has been deprecated since 2025-03-26. | Two revisions of drift. Guidance written against the older transport gives advice about mechanisms that no longer exist. |
| MCP does not define authentication, authorization or identity binding | It now does. The current revision carries a normative authorization specification requiring RFC 9728 metadata, RFC 8707 resource indicators, audience validation and PKCE — while remaining optional overall. | The single most consequential correction here. Most published MCP security writing still asserts the older position. |
| Sessions and session IDs; “Session Hijacking” as a threat | The protocol is stateless with no protocol-level sessions. The threat is now State Handle Hijacking, and session-ID guidance applies only to 2025-11-25 and earlier. | Advice about securing session identifiers is advice about a mechanism the current protocol does not have. |
OWASP LLM06 Excessive Agency; LLM07 System Prompt Leakage | In the 2026 edition, Excessive Agency is LLM03:2026; System Prompt Leakage was renamed Hidden Context Exposure and is LLM08:2026. LLM06:2026 is Unbounded Consumption and LLM07:2026 is Misinformation. | Two mappings pointed at the wrong risks. Any LLM Top 10 citation without an edition year will be wrong within a year. |
| OAuth 2.1 cited as though normative | Still an Internet-Draft — draft-ietf-oauth-v2-1, revision 15, March 2026, no RFC number. The MCP specification itself normatively depends on an earlier revision of that draft. | Describing a draft as a standard is exactly the kind of imprecision that costs credibility in a control narrative. |
| gVisor implements “over 300” Linux system calls | gVisor's own compatibility table: 288 of 351 have a full or partial implementation on linux/amd64, with 63 unsupported. What is unconditional is that no system call is passed through to the host. | The overstated number is checkable in one click, and the correct framing — interception, not implementation — is the stronger security claim anyway. |
Rego policy using rtrim; import rego.v1 presented as required | rtrim is not a Rego built-in — the function is trim_right. And since OPA 1.0, import rego.v1 is effectively a no-op, retained only for cross-version library compatibility. | A published policy that does not compile is worse than no published policy. |
| Policy validates “SQL AST structure” | The drafted policy performed uppercase substring and regular-expression matching on a raw string. That is lexical matching, not structural evaluation, and it is bypassable by comments, literals, casing and dialect syntax. | The gap between the claim and the mechanism was the most serious defect found. It is now stated as a limitation and as an architectural requirement on the enforcement point — see §08. |
| “DuneSlide” as an MCP exploit chain | CVE-2026-50548 and CVE-2026-50549 are real, both CVSS 9.8, but they are Cursor IDE sandbox-escape flaws fixed in version 3.0. Neither record nor the vendor advisory mentions MCP; the researchers list a malicious MCP server as one possible delivery channel alongside a poisoned web result. | Attributing an editor vulnerability to the protocol inflates MCP's incident record. Corrected in §11 rather than dropped, because the canonicalization lesson is genuinely transferable. |
| Storm-0558: a crash dump allowed key material to leave the secure environment | Microsoft's March 2024 addendum states plainly: “we have not found a crash dump containing the impacted key material.” The leading hypothesis remains operational error; the specific crash-dump mechanism is unconfirmed. | Presenting a vendor's stated hypothesis as established fact is the most common way security writing becomes unreliable. |
| CVE-2024-27199 as a 9.8 authentication bypass | CVE-2024-27198 is the CVSS 9.8 authentication bypass. CVE-2024-27199 is a CVSS 7.3 path traversal permitting limited administrative actions. The vendor's advisory describes them jointly, which is where the conflation comes from. | Per-CVE precision is exactly what a knowledgeable reader checks first. |
| Six functions attributed to NIST SP 800-207 | Govern / Identify / Protect / Detect / Respond / Recover are the CSF 2.0 Functions. SP 800-207 defines seven tenets of zero trust, a different document with a different purpose. | Framework conflation is the kind of error that makes an assessor doubt everything else in the mapping. |
| Phishing resistance “recommended” at AAL2 | SP 800-63B-4: “Verifiers SHALL offer at least one phishing-resistant authentication option at AAL2,” and “Federal agencies SHALL require their staff, contractors, and partners to use phishing-resistant authentication to access federal information systems.” The SHOULD applies to encouraging use. Note the scoping clause on the second sentence: it is a federal-systems requirement, not a blanket one, and dropping those five words — as an earlier draft of this page did — broadens it into something NIST did not write. | Understating a normative requirement weakens the case for a control that should not need arguing for. |
| “CSA AI Controls Matrix, AIS-04” | The identifier exists in both the AI Controls Matrix (v1.1, “Secure Application Development Lifecycle”) and the Cloud Controls Matrix (“Secure Application Design and Development”). The citation is ambiguous without naming the framework and version. | A control reference an assessor cannot resolve is not a control reference. |
What could not be verified, and is therefore not asserted
- Any count of MCP ecosystem vulnerabilities or exposed servers. Circulating figures range from nine to more than forty across the same period, none from an authoritative registry. No number appears on this page.
- The current status of the proposed HIPAA Security Rule strengthening. The rulemaking record shows neither a final rule nor a withdrawal, and the responsible pages have not been refreshed recently enough to restate it. The defensible statement is that it remains proposed and the existing rule is in force.
- Effectiveness rates for prompt-injection defences. Vendor-published detection rates are not independently reproducible and are not cited here in either direction.
- The exact release date of CSA's AI Controls Matrix v1.1, where the issuing body's own pages disagree by three weeks. The version is cited; the date is not.
18 References
Primary sources only. Every technical claim on this page traces to one of these; where a source has since been revised, the revision is what is cited.
Protocol
- Model Context Protocol specification, revision 2026-07-28 — the current revision. Statelessness, primitives, trust and safety principles.
- MCP Authorization — resource-server role, RFC 9728, RFC 8707, token handling, error semantics.
- MCP Security Best Practices — confused deputy, token passthrough, SSRF, state handle hijacking, proxy scenarios.
- MCP Authorization — security considerations — per-client consent, token audience binding, access-token privilege restriction.
- MCP Streamable HTTP transport — Origin validation, localhost binding, and the removal of protocol-level sessions.
Identity and authorization
- RFC 8693 — OAuth 2.0 Token Exchange (Proposed Standard, January 2020). Delegation versus impersonation; the
actclaim. - RFC 8707 — Resource Indicators for OAuth 2.0. The
resourceparameter and canonical resource identifiers. - RFC 9728 — OAuth 2.0 Protected Resource Metadata.
- RFC 9700 — Best Current Practice for OAuth 2.0 Security (BCP 240, January 2025). Audience restriction; implicit grant SHOULD NOT, password grant MUST NOT.
- RFC 7636 — Proof Key for Code Exchange.
- RFC 9449 — OAuth 2.0 Demonstrating Proof of Possession (DPoP).
- draft-ietf-oauth-v2-1 — The OAuth 2.1 Authorization Framework. An active Internet-Draft, cited as direction of travel and never as a standard.
- NIST SP 800-63B-4 — Authentication and Authenticator Management (July 2025). Phishing resistance at AAL2 and AAL3.
- SPIFFE / SPIRE use cases. Workload attestation and automatically rotated short-lived identities.
Frameworks and control catalogues
- NIST Cybersecurity Framework 2.0 (CSWP 29, February 2024). The six Functions.
- NIST SP 800-207 — Zero Trust Architecture. Seven tenets; no implicit trust from network location.
- NIST SP 800-53 Rev. 5, Release 5.2.0 (27 August 2025), emphasizing software update and patching controls.
- NIST SP 800-115 — Technical Guide to Information Security Testing and Assessment.
- NIST AI Risk Management Framework 1.0 (AI 100-1, January 2023). GOVERN 1.2; MANAGE 2.4.
- CIS Critical Security Controls v8.1 (June 2024). Controls 3, 5, 6, 7, 8, 12, 16, 17.
- OWASP API Security Top 10 — 2023.
- OWASP Top 10 for LLM Applications, 2026 edition (published August 2026). The identifiers used throughout §04.
- SLSA v1.2 specification. Build and Source tracks; provenance and attestation.
- CSA AI Controls Matrix v1.1. Cited by framework and version, per §17.
- MITRE ATT&CK T1078 — Valid Accounts, and M1026 — Privileged Account Management.
- Regulation (EU) 2016/679 (GDPR) — Articles 32 and 33.
- HHS — Summary of the HIPAA Security Rule. Technical safeguards at 45 CFR §164.312.
Runtime, policy and incidents
- gVisor — Linux/amd64 syscall compatibility. The 288-of-351 figure, from the project itself.
- gVisor architecture guide. The Sentry as a userspace application kernel.
- Open Policy Agent — policy reference and built-in functions. Including
trim_right, which is the function that exists. - OPA v0 compatibility. Why
import rego.v1is now a no-op. - Kubernetes auditing. Audit levels, external backends, and the memory cost of detailed capture.
- Microsoft — Storm-0558 key acquisition investigation, including the March 2024 addendum stating the crash dump was never found.
- CircleCI — incident report for the January 4, 2023 security incident.
- Okta — unauthorized access to the support case management system: root cause and remediation.
- JetBrains — CVE-2026-63077 additional guidance following reports of active exploitation, and the NVD record.
- NVD — CVE-2024-27198 and CVE-2024-27199. Note the difference in class and severity.
- Kubernetes — ingress-nginx CVE-2025-1974.
- NVD — CVE-2018-1002105. The kube-apiserver proxied-upgrade confused deputy.
- Cursor security advisory — CVE-2026-50548 / CVE-2026-50549. The primary record for the sandbox-escape flaws discussed in §11.
- Microsoft — control plane and data plane operations. The distinction this architecture borrows.