DEV Community

Imran Siddique
Imran Siddique

Posted on • Originally published at Medium on

Your Policy Engine Can Lie. Ours Can’t.

Introducing Confidential MCP, hardware-attested policy enforcement at the MCP tool boundary, running inside a Trusted Execution Environment.

An agent calls a tool. The policy engine says allow. The tool call goes through. None of that proves the policy engine itself was not compromised.

This is the ceiling that software-only MCP governance hits. It is not a theoretical ceiling. It is a structural one, and it matters for every organization deploying AI agents against sensitive data in regulated environments.

Confidential MCP (cMCP) is the answer. It launched publicly on June 23 at the Confidential Computing Summit, and the gateway and verifier are available now.

The Problem with Software-Only Governance

When your policy engine runs in the same operating system as your agent, your administrator, and your dependencies, three things become true that you cannot escape:

  • The Cedar policy on disk may not be the Cedar policy that ran. A rogue administrator can swap the bundle after approval. The hash check runs inside the same OS the administrator controls. A hash check performed by software inside a compromised OS is not a hash check. It is a controlled reading of a value the attacker controls.
  • The allow/deny decision may have been flipped in memory. A supply chain CVE in the evaluator runs in the same address space as the attacker. Memory corruption attacks that change a deny to an allow are not hypothetical in constrained AI runtimes.
  • The audit log may not reflect what actually happened. Any party holding the software signing key can reconstruct a valid audit chain after the fact. This is not speculation. It is the direct implication of holding the key outside hardware. If the key can be extracted, the log can be forged retroactively.

The control plane that governs tool calls must run where it cannot be reached by the process it governs.

That is what cMCP does.

The Architecture

cMCP is a gateway that intercepts every MCP tool call before it reaches the tool server, evaluates it against a Cedar policy bundle inside a Trusted Execution Environment, and produces a signed TRACE Trust Record as the output of every session.

Agent
  │
  ▼
cMCP Gateway (TEE: AMD SEV-SNP / Intel TDX / NVIDIA H100 CC)
  │
  ├── Cedar Policy Engine ←── Policy Bundle (measured into hardware
  │ attestation at startup, before any code
  │ runs)
  │
  ├── Tool Catalog ←── Approved tools with schema hashes, endpoint
  │ IDs, sensitivity labels, compliance domains
  │
  ├── Audit Chain ←── Hash-chained tamper-evident log, hardware-
  │ sealed
  │
  └── TRACE Claim ←── Signed by TEE key (key never leaves
  │ enclave
        │
        ▼
   Tool Server (Salesforce, Snowflake, database, API...)
Enter fullscreen mode Exit fullscreen mode

At startup, before any user code runs, the gateway measures the Cedar policy bundle hash into the hardware attestation report. This is not a hash check performed after startup. It is a hardware measurement taken at enclave boot. Changing any policy file changes the measurement. A valid attestation report with a known measurement is proof the known policy bundle ran.

Inside the TEE

The policy bundle measurement is the anchor of the entire trust chain. Here is how it flows:

  1. Enclave boot. The TEE firmware measures the image, kernel, and workload into hardware registers (PCRs for TPM, MRTD/RTMRs for TDX, GCTX.MEASUREMENT for SEV-SNP) before any user code executes.
  2. Policy bundle sealing. At cMCP gateway startup, the Cedar bundle hash is extended into the measurement chain. The attestation report the hardware produces is specific to this exact policy.
  3. Tool call interception. Every inbound MCP tool call is evaluated by the Cedar engine inside the TEE. The decision (allow / deny / redact) and the full call payload are appended to the hardware-sealed audit chain.
  4. TRACE Claim production. At session end (or per call, configurable), the gateway produces a GatewayClaim, a TRACE Trust Record signed by a key that never left the enclave.

The connectivity layer between the agent and the TEE sees ciphertext. The only thing that exits the enclave in plaintext is the signed TRACE Claim.

Cedar Policy: What Goes Inside the TEE

Cedar is a strongly-typed, formally-verifiable policy language. A Cedar policy evaluated inside a TEE combines the formal properties of Cedar with the hardware guarantees of the enclave.

// Permit tool calls from the payments workflow
permit (
  principal,
  action == cMCP::Action::"call_tool",
  resource
) when {
  context.workflow_id == "payments-processor"
};

// Block Salesforce contact queries once PII is in session
forbid (
  principal,
  action == cMCP::Action::"call_tool",
  resource == cMCP::Resource::"salesforce.contacts"
) when {
  context.session_max_sensitivity == "pii"
};

// Block anything over $10,000 without HITL approval
forbid (
  principal,
  action == cMCP::Action::"call_tool",
  resource == cMCP::Resource::"payments.authorize"
) when {
  context.amount > 10000 &&
  !context.hitl_approved
};
Enter fullscreen mode Exit fullscreen mode

Cedar evaluates forbid rules before permit rules. There is no rule ordering ambiguity. The formal semantics are the same in the TEE as they are in development: no implementation divergence, no runtime surprises.

The context.session_max_sensitivity field is the data class elevation tracker. When the first tool call touches PII, the session sensitivity label is elevated. All subsequent policy decisions in the same session have access to that fact. This prevents data class laundering, the scenario where an agent calls a PII tool early in a session and then routes the result through a nominally “public” tool that exfiltrates it.

The Tool Catalog

Before the gateway starts, the operator defines an approved tool catalog. Each catalog entry includes the tool’s schema hash and the definition hash of its approved parameters:

[
  {
    "tool_name": "salesforce.contacts",
    "server": {
      "url": "http://salesforce-mcp.internal:9001/mcp",
      "tls_fingerprint": "SHA256:...",
      "transport": "http-sse",
      "rotation_mode": "key-pinned"
    },
    "approved_definition": {
      "description": "Query Salesforce contacts by account name.",
      "input_schema": {
        "type": "object",
        "required": ["query"],
        "properties": {
          "query": {"type": "string"},
          "max_records": {"type": "integer", "default": 50}
        }
      }
    },
    "definition_hash": "sha256:b42ecf14612f23456b5b07948...",
    "compliance_domain": "pii",
    "sensitivity_level": "pii",
    "approved_by": "security-team@acme.co"
  }
]
Enter fullscreen mode Exit fullscreen mode

definition_hash is the SHA-256 of the canonical JSON of approved_definition. At runtime, the gateway rejects any tool response whose schema has drifted from the approved definition. This is the defense against MCP rug-pulls, the class of attack where a tool server sends a notifications/tools/list_changed event and silently expands the tool’s capabilities after the agent has started operating.

The TRACE Claim

Every session produces a GatewayClaim. This is a TRACE v0.1 Trust Record signed by the TEE-bound key.

{
  "eat_profile": "tag:agentrust.io,2026:trace-v0.1",
  "iat": 1750676142,
  "subject": "spiffe://trust.acme.co/agent/payments-processor/prod",

  "trace.runtime": {
    "platform": "amd-sev-snp",
    "measurement": "sha384:c9e4b1d2e3f4a5b6...",
    "rim_uri": "https://kdsintf.amd.com/vcek/v1/Milan/cert_chain"
  },

  "trace.policy": {
    "bundle_hash": "sha256:b2c3d4e5f6a7b8c9...",
    "enforcement_mode": "enforce",
    "version": "1.2.0"
  },

  "trace.cnf": {
    "jwk": {
      "kty": "EC",
      "crv": "P-256",
      "x": "x9ZBJpokJFQ_oRZzbtzo1Pqqkexd7MqEqP8wsZWdr_c",
      "y": "1Z0fdYWZI_aooZGNiqXl24SAoGmPK9e1F5-114jl8I0"
    }
  },

  "gateway.audit_chain": {
    "root": "sha256:aabbcc...",
    "tip": "sha256:ddeeff...",
    "length": 47
  },

  "signature": "Ed25519-over-canonical-JSON"
}
Enter fullscreen mode Exit fullscreen mode

The trace.policy.bundle_hash in the claim is the same hash that was measured into the hardware attestation report at startup. A verifier who checks both the hardware report and the claim confirms they match, without trusting the operator who produced either.

The gateway.audit_chain.root and tip are the hash-chain anchors of the full audit log. The verifier can check internal consistency without replaying every entry.

Hardware Providers

cMCP runs on all major TEE surfaces:

Provider auto-detects: SEV-SNP → TDX → TPM → software. In CMCP_DEV_MODE=1 the software-only provider runs without hardware, which is useful for development and CI.

The software-only provider produces structurally valid TRACE Claims but without a hardware measurement root. Any verifier enforcing hardware attestation will reject these. This is by design: dev claims and prod claims are distinguishable.

Enforcement Modes

Default is enforcing. The TRACE record reflects the enforcement mode, so a verifier can detect if a production deployment is running in advisory or silent mode. The spec requires that silent mode be explicitly configured. It is never a default.

In silent mode, the audit chain still records every would-have-denied decision. The suppression is operational (no log lines emitted to the application), not cryptographic (the decisions still appear in the TRACE Claim). This is important: silent is for baselining, not for hiding policy decisions from auditors.

Quick Start

No hardware TEE required to get started. CMCP_DEV_MODE=1 uses the software-only provider.

pip install cmcp-gateway
mkdir cmcp-demo && cd cmcp-demo
mkdir policies
Enter fullscreen mode Exit fullscreen mode

Write cmcp-config.yaml:

attestation:
  provider: auto
  enforcement_mode: advisory
policy_bundle_path: ./policies/
catalog_path: ./catalog.json
Enter fullscreen mode Exit fullscreen mode

Write policies/demo.cedar:

permit (
  principal,
  action == cMCP::Action::"call_tool",
  resource
) when {
  context.workflow_id == "demo-agent"
};
Enter fullscreen mode Exit fullscreen mode

Write policies/manifest.json:

{
  "version": "0.1.0",
  "authored_at": "2026-06-23T00:00:00Z",
  "author_identity": "you@yourcompany.com",
  "commit_sha": "demo"
}
Enter fullscreen mode Exit fullscreen mode

Start the gateway:

CMCP_DEV_MODE=1 cmcp start --config cmcp-config.yaml
Enter fullscreen mode Exit fullscreen mode

Make a tool call:

curl -X POST http://localhost:8443/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "salesforce.contacts",
      "arguments": {"query": "Acme Corp"},
      "_cmcp": {
        "session_id": "sess-001",
        "workflow_id": "demo-agent"
      }
    }
  }'
Enter fullscreen mode Exit fullscreen mode

The startup log confirms the policy bundle hash that was measured. The TRACE Claim at session end confirms the same hash appears in the hardware report. That chain, from bundle hash to hardware measurement to signed claim, is the proof.

Validating a Bundle Before Deployment

cmcp validate-bundle \
  --bundle-path ./policies/ \
  --expected-hash sha256:b2c3d4e5f6a7b8c9...
Enter fullscreen mode Exit fullscreen mode

This catches the “policy swap after approval” attack class at the CI gate. The CI pipeline computes the expected hash from the approved bundle, stores it in the deployment manifest, and validate-bundle checks it at deploy time. No trust required in the deployment pipeline; the hash check is the check.

Verifying a TRACE Claim

from cmcp_verify import verify_gateway_claim

result = verify_gateway_claim(
    claim_path="gateway-claim.json",
    expected_policy_hash="sha256:b2c3d4e5f6a7b8c9...",
    expected_subject="spiffe://trust.acme.co/agent/payments-processor/prod",
)

print(result.hardware_verified) # True if TEE attestation verifies
print(result.policy_hash_matches) # True if bundle_hash matches expected
print(result.audit_chain_valid) # True if audit chain is internally consistent
print(result.receipt_valid) # True if SCITT receipt resolves
Enter fullscreen mode Exit fullscreen mode

Verification does not require calling back to Opaque, agentrust.io, or any other third party. The verifier checks the Ed25519 signature against the TEE-bound key in cnf, validates the hardware root against the vendor’s public attestation infrastructure, and checks the SCITT receipt against the named transparency log.

How This Fits with AGT

The Agent Governance Toolkit and cMCP are designed to compose, not compete.

AGT provides the software governance layer: Cedar policy evaluation, human-in-the-loop escalation, audit trails, MCP security scanning, prompt injection detection. Every Cedar policy AGT evaluates is the same format as the bundle measured into the cMCP TEE.

The deployment path for a regulated organization:

  1. Write Cedar policies in AGT. Test in AGT’s policy sandbox.
  2. Approve the bundle through AGT’s change management workflow. AGT records the policy hash.
  3. Deploy the approved bundle into the cMCP gateway. The gateway measures it into the TEE at startup.
  4. cMCP produces TRACE Claims for every session. The TRACE Claims reference the same policy hash AGT approved.
  5. Auditors verify TRACE Claims against the AGT-approved policy hash. Hardware evidence, not operator attestation.

AGT is the software layer. cMCP is the hardware layer. TRACE is the evidence layer. They are the same Cedar policy all the way through.

Why Now

MCP’s growth as the dominant agent-to-tool protocol has made the agent action surface explicit and exploitable. Between January and February 2026, over 30 CVEs targeted MCP servers, clients, and tooling. Palo Alto Unit 42 found that with five connected MCP servers, a single compromised MCP server hit a 78.3% attack success rate.

The industry response so far has been software controls: validation, schema enforcement, content filtering. These are necessary and not sufficient. Software controls are only as trustworthy as the software stack they run on.

cMCP adds the layer that software alone cannot provide: a policy engine that runs where neither the agent, nor the operator, nor a compromised dependency can reach it. A signed record that proves what policy ran and what decisions it made, rooted in silicon attestation that predates any user code.

Get Started

pip install cmcp-gateway cmcp-verify
Enter fullscreen mode Exit fullscreen mode

Documentation: agentrust-io.github.io/cmcp GitHub: github.com/agentrust-io/cmcp Quickstart: docs/quickstart.md Discord: discord.gg/grgzFEHgkj

The project launched publicly on June 23 at the Confidential Computing Summit. The gateway, verifier, and quickstart are available now.

Top comments (0)