Internet-Draft CCS Receipt and Binding Specification August 2026
Wang Expires 5 February 2027 [Page]
Workgroup:
Internet Engineering Task Force
Internet-Draft:
draft-correctover-ccs-01
Published:
Intended Status:
Informational
Expires:
Author:
G. Wang
Correctover

Correctover Conformance Shape (CCS): A Receipt and Binding Specification for Agent Runtime Verification

Abstract

The Correctover Conformance Shape (CCS) defines a tamper-evident receipt schema and a set of cryptographic bindings that together constitute a verifiable conformance record for an agent runtime's decision to permit, deny, or escalate a tool invocation. CCS is designed as a one-receipt-per-invocation object that can be consumed by an executor-side Action Evidence Boundary (AEB), providing the request_hash, response_hash, runtime_context_hash, action binding, params_hash binding, issuer, audience, nonce/sequence, freshness, and config_hash fields that the AEB processing model requires as native inputs.

This document specifies the CCS Receipt Schema, the Canonical Configuration model, the nine binding mechanisms, key management, transport requirements, verifier source classification, conformance levels, and negative test cases. It is intended to enable a reader such as the author of the Action Evidence Boundary specification to evaluate whether and how a CCS receipt can be mapped into an Authorization Evidence Chain (AEC) component.

Status of This Memo

This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.

Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.

Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."

This Internet-Draft will expire on 5 February 2027.

Table of Contents

1. Introduction

The Correctover Conformance Shape (CCS) is a receipt-and-binding specification that produces a single, tamper-evident, cryptographically bound artifact for every tool invocation decision made by an agent runtime's governance layer. A CCS receipt answers: "Given this exact request, this exact configuration, this exact runtime context, and this exact set of rules, the verifier decided ALLOW/DENY/ESCALATE, and here is the proof."

CCS is not a policy language, an authorization framework, or a transport protocol. It is the _shape_ of the evidence that a verifier produces when it finishes evaluating a command. This evidence is intended to be consumed by downstream systems — including an executor-side Action Evidence Boundary (AEB) as defined in [I-D.schrock-action-evidence-boundary] — as one native artifact within a larger Authorization Evidence Chain (AEC).

The initial reference implementation (ccs-verifier 0.4.1) provides an in-process verifier with HMAC-SHA256 receipt signing covering the verification context (trace_id, verdict, timestamp, tool, params_hash, rule_summary). This document specifies extensions to that baseline to cover the full set of bindings that [I-D.schrock-action-evidence-boundary] Section 5.2 requires from a native artifact: request binding, response binding, runtime context binding, issuer/audience, freshness, nonce, and canonical configuration.

1.1. Scope

CCS specifies:

  • A receipt schema (Section 3) that binds a verdict to the exact invocation context.

  • A canonical configuration model (Section 4) that binds the receipt to the exact rule set and policy under which verification occurred.

  • Nine binding mechanisms (Section 5) that connect the receipt to the request bytes, response bytes, runtime context, action identity, parameter identity, issuer, audience, nonce, and freshness window.

  • Key management requirements (Section 6).

  • Transport requirements (Section 7) including fail-closed semantics.

  • Verifier source classification (Section 8).

  • Conformance levels and test vectors (Section 9 and Section 10).

CCS does NOT define:

  • A new authorization receipt format that replaces or competes with [I-D.schrock-ep-authorization-receipts]. CCS is a _verifier-side decision record_, not an organizational authorization artifact.

  • A policy language. Rules are pluggable; CCS specifies how rule outcomes are recorded and bound, not what the rules are.

  • A transport protocol for inter-process communication. The reference implementation uses in-process function calls; the out-of-process transport has been implemented with Unix-socket (tested in tests/test_unix_socket_security.py) and TCP with TLS (tested in tests/test_tls_security.py).

  • A universal evidence taxonomy. CCS defines one artifact shape for one class of decision (tool-invocation governance).

1.2. Relationship to CCS Formal Framework (DOI References)

This Internet-Draft is a protocol specification derived from and complementary to the following academic publications:

  • *DOI: 10.5281/zenodo.21271910* — "CCS Formal Framework." This paper defines the mathematical foundation: the Required(τ) ⊆ Supported(τ) conformance criterion, the transition model, and the formal proof that fail-closed enforcement satisfies the governance criterion. This I-D does not reproduce the formal framework; it specifies the wire-level receipt and binding mechanisms that implement it.

  • *DOI: 10.5281/zenodo.21603250* — "Action Receipts." This paper defines the concept of an action receipt as a tamper-evident record binding a decision to a specific action invocation. The CCS receipt in this I-D is a concrete instantiation of that concept, specialized for tool-invocation governance in agent runtimes.

  • *DOI: 10.5281/zenodo.21234580* — "CCS Standard v1.0." The overarching standard that defines the three pillars (Conformance, Reproducibility, Compliance) and the six-dimensional verification model (Structure, Schema, Latency, Cost, Identity, Integrity).

A PANW contributor cited CCS DOI in a fork of Palo-Alto-AI-Research- Lab/semantic-kernel (PR #14199, closed by Microsoft). This citation is noted as evidence of external interest in the CCS DOI; it does not constitute adoption by Microsoft or the Semantic Kernel project.

2. Terminology

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

*CCS-specific terms:*

*Command*: An immutable, structured representation of a tool invocation request, comprising at minimum: agent_id, tool name, parameters, timestamp, and trace_id. The Command is the input to verification.

*Verifier*: A component that evaluates a Command against a set of Rules and produces a VerificationResult. The verifier MAY run in- process (same address space as the agent) or out-of-process (separate address space, separate crash domain).

*Rule*: A pluggable unit of policy evaluation. A Rule accepts a Command and returns a RuleResult with a verdict (allow, deny, escalate), an optional reason string, and a latency measurement.

*VerificationResult*: The output of a verification. Contains the verdict, signed receipt, rule results, and metadata.

*Receipt*: A truncated HMAC-SHA256 (or Ed25519, per Section 6) digest that binds the verification context to a shared secret or signing key, providing tamper-evident audit.

*Config Hash*: A SHA-256 digest of the canonical JSON representation of the verifier's configuration (rule set, policy version, signing key identifier). Binds the receipt to the exact policy under which verification occurred.

*Fail-closed*: A property of the enforcement mechanism whereby any failure in the verification path — exception, timeout, missing input, ambiguous state — results in the tool invocation being blocked, not allowed. This is the opposite of fail-open (CWE-636).

*Conformance Shape*: The complete set of fields, bindings, and semantic constraints that a CCS receipt MUST satisfy to be considered conformant at a given level.

3. CCS Receipt Schema

3.1. Field Definitions

A conforming CCS Receipt is a JSON object conforming to I-JSON [RFC7493]. The following table defines each field. Fields marked "Implemented" are present in ccs-verifier 0.4.1. Fields marked "Specified, not yet implemented" are defined by this specification but are not yet present in the 0.4.1 reference implementation.

+====================+========+===========+===========+=================+
|Field               |Type    |Status     |Required   |Description      |
+====================+========+===========+===========+=================+
|trace_id            |string  |Implemented|MUST       |SHA-256 of       |
|                    |(16-char|           |           |time.time_ns(),  |
|                    |hex)    |           |           |truncated to 16  |
|                    |        |           |           |hex chars.       |
|                    |        |           |           |Uniquely         |
|                    |        |           |           |identifies this  |
|                    |        |           |           |verification     |
|                    |        |           |           |event.           |
+--------------------+--------+-----------+-----------+-----------------+
|verdict             |string  |Implemented|MUST       |One of: "allow", |
|                    |enum    |           |           |"deny",          |
|                    |        |           |           |"escalate".  The |
|                    |        |           |           |governance       |
|                    |        |           |           |decision.        |
+--------------------+--------+-----------+-----------+-----------------+
|timestamp           |float   |Implemented|MUST       |Unix timestamp   |
|                    |        |           |           |(time.time()) at |
|                    |        |           |           |which the verdict|
|                    |        |           |           |was finalized.   |
|                    |        |           |           |Float precision. |
+--------------------+--------+-----------+-----------+-----------------+
|tool                |string  |Implemented|MUST       |The tool name    |
|                    |        |           |           |from the Command.|
|                    |        |           |           |Identifies which |
|                    |        |           |           |tool invocation  |
|                    |        |           |           |was verified.    |
+--------------------+--------+-----------+-----------+-----------------+
|params_hash         |string  |Implemented|MUST       |SHA-256 of       |
|                    |(16-char|           |           |canonical JSON of|
|                    |hex)    |           |           |the              |
|                    |        |           |           |Command.params   |
|                    |        |           |           |dict, truncated  |
|                    |        |           |           |to 16 hex chars. |
+--------------------+--------+-----------+-----------+-----------------+
|rule_summary        |string  |Implemented|MUST       |Pipe-delimited   |
|                    |        |           |           |list of          |
|                    |        |           |           |rule_name=verdict|
|                    |        |           |           |pairs, in rule   |
|                    |        |           |           |evaluation order.|
+--------------------+--------+-----------+-----------+-----------------+
|receipt             |string  |Implemented|MUST       |HMAC-SHA256 over |
|                    |(32-char|           |           |the signed bytes |
|                    |hex)    |           |           |(Section 3.2),   |
|                    |        |           |           |truncated to 32  |
|                    |        |           |           |hex chars.       |
+--------------------+--------+-----------+-----------+-----------------+
|verified_at         |float   |Implemented|MUST       |Unix timestamp of|
|                    |        |           |           |verification.    |
|                    |        |           |           |May differ from  |
|                    |        |           |           |timestamp if     |
|                    |        |           |           |post-processing  |
|                    |        |           |           |occurred.        |
+--------------------+--------+-----------+-----------+-----------------+
|block_reason        |string  |Implemented|Conditional|Human-readable   |
|                    |        |           |           |reason for deny/ |
|                    |        |           |           |escalate         |
|                    |        |           |           |verdicts.  MUST  |
|                    |        |           |           |be empty string  |
|                    |        |           |           |for allow.       |
+--------------------+--------+-----------+-----------+-----------------+
|request_hash        |string  |Specified, |MUST       |SHA-256 of the   |
|                    |(hex)   |not yet    |           |canonical bytes  |
|                    |        |implemented|           |of the original  |
|                    |        |           |           |request as       |
|                    |        |           |           |received by the  |
|                    |        |           |           |verifier.  Binds |
|                    |        |           |           |receipt to exact |
|                    |        |           |           |request bytes    |
|                    |        |           |           |(Section 5.1).   |
+--------------------+--------+-----------+-----------+-----------------+
|response_hash       |string  |Specified, |SHOULD     |SHA-256 of the   |
|                    |(hex)   |not yet    |           |tool response    |
|                    |        |implemented|           |bytes, computed  |
|                    |        |           |           |after invocation.|
|                    |        |           |           |Binds receipt to |
|                    |        |           |           |exact response   |
|                    |        |           |           |(Section 5.2).   |
+--------------------+--------+-----------+-----------+-----------------+
|runtime_context_hash|string  |Specified, |SHOULD     |SHA-256 of       |
|                    |(hex)   |not yet    |           |canonical JSON of|
|                    |        |implemented|           |runtime context  |
|                    |        |           |           |(caller identity,|
|                    |        |           |           |tenant,          |
|                    |        |           |           |environment).    |
|                    |        |           |           |Binds receipt to |
|                    |        |           |           |execution        |
|                    |        |           |           |environment      |
|                    |        |           |           |(Section 5.3).   |
+--------------------+--------+-----------+-----------+-----------------+
|action              |string  |Specified, |MUST       |The CAID-        |
|                    |        |not yet    |           |compatible action|
|                    |        |implemented|           |identifier for   |
|                    |        |           |           |this invocation. |
|                    |        |           |           |Enables AEC      |
|                    |        |           |           |matching         |
|                    |        |           |           |(Section 5.4).   |
+--------------------+--------+-----------+-----------+-----------------+
|config_hash         |string  |Specified, |MUST       |SHA-256 of the   |
|                    |(hex)   |not yet    |           |canonical        |
|                    |        |implemented|           |configuration    |
|                    |        |           |           |(Section 4).     |
|                    |        |           |           |Binds receipt to |
|                    |        |           |           |exact rule set.  |
+--------------------+--------+-----------+-----------+-----------------+
|issuer              |string  |Specified, |MUST       |Identifier of the|
|                    |(URI)   |not yet    |           |verifier that    |
|                    |        |implemented|           |produced this    |
|                    |        |           |           |receipt          |
|                    |        |           |           |(Section 5.6).   |
+--------------------+--------+-----------+-----------+-----------------+
|audience            |string  |Specified, |MUST       |Identifier of the|
|                    |(URI)   |not yet    |           |intended consumer|
|                    |        |implemented|           |of this receipt  |
|                    |        |           |           |(Section 5.7).   |
+--------------------+--------+-----------+-----------+-----------------+
|nonce               |string  |Specified, |MUST       |Unpredictable,   |
|                    |(hex)   |not yet    |           |single-use value |
|                    |        |implemented|           |for replay       |
|                    |        |           |           |prevention       |
|                    |        |           |           |(Section 5.8).   |
+--------------------+--------+-----------+-----------+-----------------+
|sequence            |integer |Specified, |SHOULD     |Monotonically    |
|                    |        |not yet    |           |increasing       |
|                    |        |implemented|           |counter per      |
|                    |        |           |           |issuer for       |
|                    |        |           |           |ordering         |
|                    |        |           |           |(Section 5.8).   |
+--------------------+--------+-----------+-----------+-----------------+
|issued_at           |float   |Specified, |MUST       |Unix timestamp   |
|                    |        |not yet    |           |when the receipt |
|                    |        |implemented|           |was issued       |
|                    |        |           |           |(distinct from   |
|                    |        |           |           |timestamp).      |
|                    |        |           |           |(Section 5.9).   |
+--------------------+--------+-----------+-----------+-----------------+
|expires_at          |float   |Specified, |MUST       |Unix timestamp   |
|                    |        |not yet    |           |after which this |
|                    |        |implemented|           |receipt MUST NOT |
|                    |        |           |           |be accepted.     |
|                    |        |           |           |(Section 5.9).   |
+--------------------+--------+-----------+-----------+-----------------+
|max_clock_skew      |float   |Specified, |SHOULD     |Maximum          |
|                    |        |not yet    |           |acceptable clock |
|                    |        |implemented|           |skew in seconds. |
|                    |        |           |           |Default: 30.0.   |
|                    |        |           |           |(Section 5.9).   |
+--------------------+--------+-----------+-----------+-----------------+
Figure 1

3.2. Signed Bytes

The receipt field in the 0.4.1 reference implementation is computed by the sign_receipt function as follows:

*Signing payload construction (0.4.1, Implemented):*

payload = "{trace_id}:{verdict}:{timestamp}:{tool}:{params_hash}:{rule_summary}"

Each field is interpolated using its string representation. The timestamp is the Python float from time.time(). The payload is then encoded as UTF-8.

*Algorithm (0.4.1, Implemented):*

receipt = HMAC-SHA256(secret, payload.encode("utf-8")).hexdigest()[:32]

Where secret is a 32-byte key (generated via secrets.token_bytes(32) if not provided). The output is truncated to the first 32 hexadecimal characters of the full 64-character hex digest.

*Extended signing payload (Specification, for AEC mapping):* When the extended fields (Section 3.1, "Specified, not yet implemented") are present, the signing payload MUST be extended to include them:

extended_payload = "{trace_id}:{verdict}:{timestamp}:{tool}:{params_hash}:{rule_summary}:{request_hash}:{response_hash}:{runtime_context_hash}:{action}:{config_hash}:{issuer}:{audience}:{nonce}:{sequence}:{issued_at}:{expires_at}"

The extended receipt MUST use HMAC-SHA256 with the same truncation (32 hex chars) or MUST use Ed25519 as specified in Section 6, with the full 64-byte hex digest.

*Critical property:* The signed bytes cover the full verification context. Any change to any signed field — the tool name, the parameters, the verdict, the timestamp, the rule summary — invalidates the receipt. This is what makes the receipt tamper- evident.

3.3. Receipt JSON Example

The following is an example CCS receipt as produced by ccs-verifier 0.4.1 (Implemented fields only):

{
  "trace_id": "a1b2c3d4e5f67890",
  "verdict": "deny",
  "timestamp": 1722384000.123456,
  "tool": "shell_exec",
  "params_hash": "f9e8d7c6b5a43210",
  "rule_summary": "ssrf_protection=allow|rce_protection=deny",
  "receipt": "0123456789abcdef0123456789abcdef",
  "verified_at": 1722384000.123890,
  "block_reason": "RCE pattern detected: (rm\\s+-rf\\s+/)"
}

The following example shows the extended receipt with AEC-mappable fields (Specified, not yet implemented):

{
  "trace_id": "a1b2c3d4e5f67890",
  "verdict": "allow",
  "timestamp": 1722384000.123456,
  "tool": "search_web",
  "params_hash": "1234567890abcdef",
  "rule_summary": "ssrf_protection=allow|rce_protection=allow|credential_leak=allow",
  "receipt": "fedcba9876543210fedcba9876543210",
  "verified_at": 1722384000.123890,
  "block_reason": "",
  "request_hash": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
  "response_hash": "",
  "runtime_context_hash": "sha256:7d865e959b2466918c180089997d8745e10a3ef4b8d17e2a6c7b9f3e2d1a0c8b",
  "action": "ccs:tool-invoke:search_web:sha256:1234567890abcdef",
  "config_hash": "sha256:aabbccdd00112233445566778899aabbccdd00112233445566778899aabbccdd",
  "issuer": "https://verifier.example.com/ccs/v1",
  "audience": "https://executor.example.com/aeb",
  "nonce": "f47ac10b58cc4372a5670e02b2c3d479",
  "sequence": 42,
  "issued_at": 1722384000.123000,
  "expires_at": 1722384060.123000,
  "max_clock_skew": 30.0
}

4. Canonical Configuration

4.1. Canonical Config Fields

A CCS Canonical Configuration is a JSON object that describes the exact state of the verifier at the time a receipt was issued. It MUST contain:

 +==================+==========+==========+=======================+
 | Field            | Type     | Required | Description           |
 +==================+==========+==========+=======================+
 | rules            | array of | MUST     | Ordered list of rule  |
 |                  | strings  |          | names as registered.  |
 +------------------+----------+----------+-----------------------+
 | policy_version   | string   | MUST     | Version identifier of |
 |                  |          |          | the policy governing  |
 |                  |          |          | rule evaluation.      |
 +------------------+----------+----------+-----------------------+
 | signing_key_id   | string   | MUST     | Identifier of the     |
 |                  |          |          | signing key used for  |
 |                  |          |          | this receipt.         |
 +------------------+----------+----------+-----------------------+
 | verifier_version | string   | MUST     | Software version of   |
 |                  |          |          | the verifier.         |
 +------------------+----------+----------+-----------------------+
 | schema_version   | string   | MUST     | Version of the CCS    |
 |                  |          |          | receipt schema (e.g., |
 |                  |          |          | "1.2").               |
 +------------------+----------+----------+-----------------------+
 | deployment_mode  | string   | MUST     | "in-process" or "out- |
 |                  | enum     |          | of-process".          |
 +------------------+----------+----------+-----------------------+
Figure 2

Example canonical config:

{
  "rules": ["ssrf_protection", "rce_protection", "credential_leak"],
  "policy_version": "2026-07-01",
  "signing_key_id": "key-2026-07-01-primary",
  "verifier_version": "0.4.1",
  "schema_version": "1.2",
  "deployment_mode": "in-process"
}

4.2. Canonicalization Algorithm

The canonical configuration MUST be serialized using JSON Canonicalization Scheme (JCS) as defined in [RFC8785]:

import json

def canonical_config(config: dict) -> bytes:
    """Serialize config to canonical JSON per RFC 8785 (JCS)."""
    return json.dumps(
        config,
        sort_keys=True,
        separators=(",", ":"),
        ensure_ascii=True,
        allow_nan=False
    ).encode("utf-8")

Key properties:

  • Keys are sorted lexicographically.

  • No whitespace between tokens (compact form).

  • ASCII-only encoding with \uXXXX escapes for non-ASCII.

  • NaN and Infinity are not permitted (must serialize as strings or reject).

4.3. Config Hash

The config_hash is computed as:

config_hash = hashlib.sha256(canonical_config(config)).hexdigest()

The config_hash MUST be included in the extended signing payload (Section 3.2) when the extended fields are in use. This binds the receipt to the exact rule set and policy version, preventing a verifier from being reconfigured after issuing a receipt and having the old receipt still validate under the new configuration.

5. Bindings

This section defines the nine binding mechanisms that connect a CCS receipt to the various elements of the invocation lifecycle. These bindings are designed to satisfy the native artifact verification requirements of [I-D.schrock-action-evidence-boundary] Section 5.2, enabling the CCS receipt to participate in CAID matching (Section 5.3 of [I-D.schrock-action-evidence-boundary]) and AEC evidence satisfaction (Section 5.4 of [I-D.schrock-action-evidence-boundary]).

5.1. request_hash Binding

*Purpose:* Bind the receipt to the exact request bytes as received by the verifier.

*Mechanism:*

The verifier MUST compute request_hash as the SHA-256 digest of the canonical bytes of the request that triggered verification. The canonical bytes are defined as the Command.canonical_bytes() output from the reference implementation:

def canonical_bytes(command) -> bytes:
    return json.dumps({
        "agent_id": command.agent_id,
        "tool": command.tool,
        "params": command.params,
        "timestamp": command.timestamp,
        "trace_id": command.trace_id,
    }, sort_keys=True, separators=(",", ":")).encode("utf-8")

request_hash = "sha256:" + hashlib.sha256(canonical_bytes(command)).hexdigest()

*Binding strength:* The request_hash changes if any material field of the request changes — the tool name, the parameters, the agent_id, or the trace_id. An attacker who modifies the request after verification will produce a different request_hash, breaking the binding.

*Status:* Specified, not yet implemented in ccs-verifier 0.4.1. The 0.4.1 implementation binds via params_hash (16-char truncation) which covers only the parameters, not the full request context.

5.2. response_hash Binding

*Purpose:* Bind the receipt to the exact response produced by the tool invocation.

*Mechanism:*

After the tool is invoked and a response is produced, the verifier (or a post-invocation hook) MUST compute:

response_hash = "sha256:" + hashlib.sha256(response_bytes).hexdigest()

Where response_bytes is the exact byte representation of the tool's response. For string responses, this is the UTF-8 encoding. For structured responses, the canonical JSON serialization MUST be used.

*Binding strength:* The response_hash enables a downstream consumer to verify that the response they received is the same response that was observed at verification time. If the response is modified in transit, the hash will not match.

*Timing:* The response_hash MUST be computed after the tool invocation completes. It is appended to the receipt as a post-hoc binding, not part of the pre-invocation signed bytes. If the response_hash is absent, the receipt still covers the pre-invocation decision but does not bind to the response.

*Status:* Specified, not yet implemented.

5.3. runtime_context_hash Binding

*Purpose:* Bind the receipt to the runtime execution environment.

*Mechanism:*

The runtime context is a JSON object containing environment-scoped fields:

{
  "caller_identity": "agent-001",
  "tenant": "acme-corp",
  "environment": "production",
  "process_id": 12345,
  "hostname": "worker-42",
  "network_namespace": "ns-prod"
}

The runtime_context_hash is computed as:

context_bytes = json.dumps(context, sort_keys=True, separators=(",", ":")).encode("utf-8")
runtime_context_hash = "sha256:" + hashlib.sha256(context_bytes).hexdigest()

*Binding strength:* Prevents a receipt issued in one environment (e.g., staging) from being replayed in another (e.g., production). The receipt is bound to the exact runtime context in which verification occurred.

*Status:* Specified, not yet implemented.

5.4. action Binding

*Purpose:* Provide a CAID-compatible action identifier that enables the CCS receipt to participate in the AEB's CAID matching process ([I-D.schrock-action-evidence-boundary] Section 5.3).

*Mechanism:*

The action field is a string identifier constructed as:

action = "ccs:tool-invoke:{tool_name}:{params_hash}"

Where {tool_name} is the tool name from the Command and {params_hash}
is the full SHA-256 hex digest (not truncated) of the canonical
parameters.

For AEC integration, this action identifier MUST be mappable to a CAID action-type definition via a relying-party-pinned mapping profile ([I-D.schrock-action-evidence-boundary] Section 5.3). The mapping profile MUST specify:

  • The source media type: "application/x-ccs-receipt+json"

  • The target action type: the CAID action-type definition

  • The material fields: tool, params (via params_hash), and any additional fields the relying party considers material.

*Status:* Specified, not yet implemented.

5.5. params_hash Binding

*Purpose:* Bind the receipt to the exact tool parameters.

*Mechanism (Implemented in 0.4.1):*

def params_hash(params: dict) -> str:
    return hashlib.sha256(
        json.dumps(params, sort_keys=True, separators=(",", ":")).encode()
    ).hexdigest()[:16]

The 0.4.1 implementation truncates to 16 hex characters (64 bits). This provides collision resistance of approximately 2^32 under birthday attack, which is sufficient for audit uniqueness within a single verifier instance but MAY be insufficient for cross-verifier replay prevention in high-volume deployments.

*Recommendation:* Implementations targeting conformance Level 2 or above (Section 9) SHOULD use the full 64-character SHA-256 hex digest for params_hash.

*Status:* Implemented (16-char truncation) in 0.4.1.

5.6. issuer Binding

*Purpose:* Identify the verifier that produced the receipt, enabling the AEB to dispatch verification to the correct native verifier adapter ([I-D.schrock-action-evidence-boundary] Section 5.2).

*Mechanism:*

The issuer field is a URI that identifies the verifier instance:

issuer = "https://verifier.example.com/ccs/v1"

The URI MUST be stable across key rotations. The issuer identifier MUST be covered by the signing mechanism (HMAC or Ed25519) so that an attacker cannot substitute a different issuer without invalidating the receipt.

*Status:* Specified, not yet implemented.

5.7. audience Binding

*Purpose:* Identify the intended consumer of the receipt, preventing receipt misdirection ([I-D.schrock-action-evidence-boundary] Section 4).

*Mechanism:*

The audience field is a URI that identifies the intended recipient:

audience = "https://executor.example.com/aeb"

A receipt whose audience does not match the consumer MUST be rejected. This prevents an attacker from presenting a receipt intended for one executor to a different executor.

*Status:* Specified, not yet implemented.

5.8. nonce/sequence Binding

*Purpose:* Prevent replay of previously-issued receipts.

*Mechanism:*

The nonce field is a cryptographically random, single-use value:

nonce = secrets.token_hex(16)

The sequence field is a monotonically increasing integer counter scoped to the issuer:

sequence = atomic_increment(per_issuer_counter)

*Anti-replay enforcement:*
  • The consumer MUST maintain a replay cache of seen (issuer, nonce) pairs.

  • A receipt with a previously-seen nonce MUST be rejected.

  • The replay cache MUST persist across process restarts.

  • The sequence field provides an additional ordering guarantee: a receipt with sequence number N MUST NOT be accepted if a receipt with sequence number N+1 has already been accepted from the same issuer.

*Status:* Specified, not yet implemented.

5.9. freshness Binding (issued_at + expires_at + max_clock_skew)

*Purpose:* Bound the temporal validity of the receipt.

*Mechanism:*

Three fields work together to enforce freshness:

  • issued_at: Unix timestamp when the receipt was issued.

  • expires_at: Unix timestamp after which the receipt MUST NOT be accepted.

  • max_clock_skew: Maximum acceptable clock skew in seconds between the issuer and the consumer. Default: 30.0 seconds.

*Validation algorithm:*

def check_freshness(receipt, local_time, max_clock_skew=30.0):
    skew = receipt.max_clock_skew or 30.0
    if local_time < receipt.issued_at - skew:
        return False
    if local_time > receipt.expires_at + skew:
        return False
    return True

*Recommended expiry:* For tool-invocation governance, an expires_at of issued_at + 60 seconds is RECOMMENDED. The exact window depends on the risk profile of the action being governed.

*Status:* Specified, not yet implemented.

6. Key Management

6.1. Key Generation

*HMAC-SHA256 (Implemented in 0.4.1):*

The signing key MUST be generated using a cryptographically secure random number generator:

signing_key = secrets.token_bytes(32)

The key MUST NOT be derived from predictable sources (timestamps, process IDs, weak PRNGs).

*Ed25519 (Specification, for cross-domain verification):*

For deployments where the verifier and consumer are in separate trust domains (e.g., out-of-process verification across organizational boundaries), Ed25519 key pairs SHOULD be used:

from cryptography.hazmat.primitives.asymmetric.ed25519 import (
    Ed25519PrivateKey, Ed25519PublicKey
)
private_key = Ed25519PrivateKey.generate()
public_key = private_key.public_key()

The private key signs the receipt; the public key is distributed out- of-band for verification. This prevents the consumer from forging receipts.

6.2. Key Enrollment

Before a CCS receipt can be verified by a consumer, the consumer MUST have enrolled the verifier's key:

  • *HMAC:* The shared secret MUST be distributed via a secure channel (e.g., configuration management system, secrets manager). The key MUST NOT be transmitted in-band with the receipt.

  • *Ed25519:* The public key MUST be pinned by the consumer via an out-of-band mechanism (configuration file, environment variable, or trust anchor store). The key fingerprint (SHA-256 of the raw public key bytes) SHOULD be used as the signing_key_id.

6.3. Key Rotation

Key rotation MUST follow a phased approach:

  1. *Announce:* The verifier publishes the new key identifier and effective date.

  2. *Dual-sign:* During the overlap window, receipts are signed with both old and new keys. The receipt field contains the signature under the current key; an additional receipt_prev field contains the signature under the previous key.

  3. *Cutover:* After the overlap window, only the new key is used.

  4. *Retire:* The old key is retired after all receipts signed under it have expired (per expires_at).

The overlap window MUST be at least 2x the maximum receipt lifetime (expires_at - issued_at) to ensure no unexpired receipts are left without a valid key.

6.4. Verifier-Operator Separation

A fundamental security property of CCS is the separation between the verifier (which evaluates rules and signs receipts) and the operator (the agent runtime that invokes tools).

*In-process (0.4.1):* The verifier and operator share the same address space. The signing key is held in the verifier's memory. A compromised agent process CAN access the signing key. This is a known limitation documented in the reference implementation.

*Out-of-process (Specified):* The verifier runs in a separate process with its own memory space, file descriptors, and crash domain. The signing key is held only in the verifier process. A compromised agent process CANNOT access the signing key. This is the RECOMMENDED deployment mode for security-critical applications.

7. Transport Requirements

7.1. Fail-Closed Semantics

CCS enforcement MUST be fail-closed. This is the core security guarantee, derived from the formal framework [CCS-FORMAL] and implemented in the reference implementation.

*Requirement:* If the verifier raises an exception, times out, returns an ambiguous result, or is unreachable, the tool invocation MUST be blocked.

*Implementation in 0.4.1:*

The govern() wrapper in the CCS SDK intercepts the tool function call and calls verifier.verify() before invoking the original function. If verify() raises any exception, the wrapper catches it and raises a PermissionError, blocking the tool invocation.

def govern(fn, policy="default"):
    def wrapper(*args, **kwargs):
        try:
            result = verifier.verify(command)
            if not result.allowed:
                raise PermissionError(result.block_reason)
        except Exception:
            raise PermissionError("Verification failed")
        return fn(*args, **kwargs)
    return wrapper

This is the fundamental difference from observer-pattern hooks (which fail-open when the observer crashes, as documented in [CWE-636]).

7.2. Timeout Behavior

*Verifier timeout:* If the verifier does not respond within the configured timeout (default: 5000ms for out-of-process, unlimited for in-process), the invocation MUST be blocked.

*Receipt timeout:* The expires_at field (Section 5.9) provides an upper bound on receipt validity. A receipt that has expired MUST be rejected even if all other fields are valid.

*Combined:* Both timeouts are independent and both MUST be enforced. A receipt that was issued quickly but has since expired MUST still be rejected.

7.3. In-Process vs Out-of-Process Deployment

   +==================+==================+=======================+
   | Property         | In-Process       | Out-of-Process        |
   +==================+==================+=======================+
   | Process boundary | None (shared     | Full (separate        |
   |                  | address space)   | process)              |
   +------------------+------------------+-----------------------+
   | Signing key      | Vulnerable to    | Protected             |
   | exposure         | agent compromise |                       |
   +------------------+------------------+-----------------------+
   | Crash isolation  | None (shared     | Full (verifier        |
   |                  | crash domain)    | survives agent crash) |
   +------------------+------------------+-----------------------+
   | Latency          | ~6µs P50         | ~100µs P50 (gRPC      |
   |                  | (Python)         | overhead)             |
   +------------------+------------------+-----------------------+
   | Implementation   | Implemented      | Implemented (0.4.1):  |
   | status           | (0.4.1)          | Unix-socket transport |
   |                  |                  | (tests/test_unix_socket|
   |                  |                  | _security.py); TCP with|
   |                  |                  | TLS (tests/test_tls_   |
   |                  |                  | security.py)           |
   +------------------+------------------+-----------------------+
   | Conformance      | Level 0-1        | Level 2-3             |
   | level            |                  |                       |
   +------------------+------------------+-----------------------+
Figure 3

*Note on performance:* The P50/P99 latency figures above are informational measurements from the reference implementation and early deployments. They are not normative requirements. Actual latency depends on hardware, operating system, rule complexity, and deployment configuration.

8. Verifier Source Classification

This section classifies verifiers by their provenance and the level of assurance a relying party SHOULD place in their verdicts.

8.1. Class A: Self-Built Verifier

A verifier whose rule set, signing key, and configuration are built, operated, and audited entirely by the relying party's own organization.

*Properties:*

  • The relying party has full visibility into the source code, rule definitions, and signing key management.

  • The relying party can independently verify that the verifier implements fail-closed semantics correctly.

  • The signing key is generated and held entirely within the relying party's infrastructure.

*Assurance:* Highest. The relying party trusts the verifier because they built it and control every aspect of its operation.

*AEC mapping:* A Class A verifier's receipt is directly consumable as a policy-permit evidence component in an AEC, subject to CAID matching.

8.2. Class B: Audited Verifier

A verifier built by a third party but subjected to independent audit by the relying party or a trusted auditor.

*Properties:*

  • The source code is available for review (may be open source or provided under NDA).

  • An independent audit has verified that the implementation matches the specification, particularly fail-closed semantics and signing correctness.

  • The audit report is available to the relying party.

*Assurance:* High, contingent on audit scope and freshness. The relying party trusts the verifier because a trusted auditor has verified it.

*AEC mapping:* A Class B verifier's receipt is consumable as a policy-permit evidence component, but the relying party SHOULD document the audit basis and any residual risk.

8.3. Class C: Self-Declared Verifier

A verifier whose operator claims conformance to CCS but has not submitted to independent audit.

*Properties:*

  • The operator declares that the verifier implements CCS correctly.

  • No independent verification of the implementation has occurred.

  • The relying party has no direct evidence that fail-closed semantics are correctly implemented.

*Assurance:* Low. The relying party trusts the verifier based on the operator's assertion alone.

*AEC mapping:* A Class C verifier's receipt MAY be consumed as evidence, but the relying party's AEC requirement SHOULD weight it lower than Class A or Class B. A relying party with a strict evidence policy MAY reject Class C receipts entirely.

9. Conformance Levels

9.1. Level 0-3 Definitions

*Level 0 — Baseline (Implemented in 0.4.1):*

The verifier produces a signed receipt covering: trace_id, verdict, timestamp, tool, params_hash, rule_summary. Fail-closed enforcement is implemented. In-process deployment only.

A Level 0 implementation satisfies the core tamper-evident audit requirement but does not provide the bindings necessary for AEC composition.

*Level 1 — Extended Bindings:*

In addition to Level 0, the verifier produces receipts with: request_hash, config_hash. The receipt binds to the exact request bytes and the exact configuration.

A Level 1 implementation provides stronger replay resistance (via request_hash) and configuration binding (via config_hash).

*Level 2 — Full AEC Readiness:*

In addition to Level 1, the verifier produces receipts with: response_hash, runtime_context_hash, action (CAID-compatible), issuer, audience, nonce, sequence, issued_at, expires_at, max_clock_skew. Ed25519 signing is supported as an alternative to HMAC.

A Level 2 implementation provides all bindings necessary for the receipt to be consumed as a native artifact by an AEB per [I-D.schrock-action-evidence-boundary].

*Level 3 — Out-of-Process with Full Isolation:*

In addition to Level 2, the verifier operates out-of-process with a fully implemented gRPC transport. The signing key is held only in the verifier process. Cross-replica replay prevention is implemented via shared durable state.

A Level 3 implementation provides the strongest security guarantees: process isolation, key protection, and distributed replay prevention.

9.2. Conformance Vectors (Positive Test Cases)

Each conformance vector is a self-contained test case that a conforming implementation MUST pass.

*CV-001: Basic ALLOW receipt (Level 0)*

Input Command:
  agent_id: "test-agent"
  tool: "search_web"
  params: {"query": "weather in Tokyo"}

Expected:
  verdict: "allow"
  receipt: valid HMAC-SHA256 over the signed bytes
  rule_summary: contains all registered rules with verdict=allow

*CV-002: Basic DENY receipt (Level 0)*

Input Command:
  agent_id: "test-agent"
  tool: "shell_exec"
  params: {"command": "rm -rf /"}
Expected:
verdict: "deny" block_reason: non-empty, describes the RCE pattern receipt: valid HMAC-SHA256 covering the deny verdict rule_summary: contains rce_protection=deny

*CV-003: Config hash binding (Level 1)*

Given two verifiers with different rule sets,
when they verify the same command,
then their config_hash values MUST differ.

*CV-004: Request hash binding (Level 1)*

Given the same tool and rule set,
when two commands differ only in params,
then their request_hash values MUST differ.

*CV-005: Issuer/audience binding (Level 2)*

Given a receipt with issuer="A" and audience="B",
when consumer "C" receives the receipt,
then consumer "C" MUST reject the receipt (audience mismatch).

*CV-006: Freshness enforcement (Level 2)*

Given a receipt with expires_at=T,
when consumer receives the receipt at time T+1,
then the consumer MUST reject the receipt.

10. Negative Test Cases

This section defines eight negative test cases that a conforming CCS implementation MUST detect and reject. Each test case specifies the attack scenario, the expected receipt change, the expected verdict, and the detection condition.

These negative cases are designed to demonstrate that the bindings defined in Section 5 are load-bearing: removing any one binding reopens the corresponding attack.

10.1. Changed Arguments

*Scenario:* An attacker intercepts a valid receipt for tool invocation A, modifies the tool parameters, and presents the modified command with the original receipt.

*Expected receipt change:* The params_hash (and request_hash at Level 1+) in the receipt no longer matches the modified parameters. The HMAC verification fails because the signed bytes have changed.

*Expected verdict:* DENY.

*Detection condition:*

recomputed_params_hash = compute_params_hash(modified_params)
assert recomputed_params_hash != receipt.params_hash

*Binding defeated if removed:* params_hash binding (Section 5.5).

10.2. Changed Response

*Scenario:* An attacker intercepts the tool's response, modifies it, and presents the modified response to the downstream consumer along with the original receipt.

*Expected receipt change:* The response_hash in the receipt no longer matches the modified response bytes.

*Expected verdict:* The receipt is still valid for the pre-invocation decision (the verifier did allow the invocation), but the downstream consumer detects the response mismatch and rejects the response.

*Detection condition:*

recomputed_response_hash = hashlib.sha256(modified_response_bytes).hexdigest()
assert recomputed_response_hash != receipt.response_hash
*Binding defeated if removed:* response_hash binding (Section 5.2).

*Note:* This is a post-invocation binding. The 0.4.1 implementation does not include response_hash; the attack is undetectable at Level 0.

10.3. Replay

*Scenario:* An attacker captures a valid receipt for a one-time action (e.g., "transfer $100 to account X") and replays it to authorize a second invocation of the same action.

*Expected receipt change:* The nonce in the receipt has already been recorded in the consumer's replay cache.

*Expected verdict:* DENY (replay detected).

*Detection condition:*

if (receipt.issuer, receipt.nonce) in replay_cache:
return DENY

*Binding defeated if removed:* nonce/sequence binding (Section 5.8).

*Note:* The 0.4.1 implementation does not include nonce; replay detection is not possible at Level 0 except via the in-process audit log (which is not durable across restarts).

10.4. Stale Evidence

*Scenario:* An attacker presents a receipt that was issued 24 hours ago for a time-sensitive action (e.g., a stock trade).

*Expected receipt change:* The expires_at field in the receipt has passed.

*Expected verdict:* DENY (expired receipt).

*Detection condition:*

if current_time > receipt.expires_at + receipt.max_clock_skew:
return DENY

*Binding defeated if removed:* freshness binding (Section 5.9).

*Note:* The 0.4.1 implementation does not include expires_at; stale receipts are not detectable at Level 0.

10.5. Wrong Audience

*Scenario:* An attacker obtains a receipt intended for Executor A and presents it to Executor B, hoping that Executor B will accept it as authorization for the same action.

*Expected receipt change:* The audience field in the receipt identifies Executor A, not Executor B.

*Expected verdict:* DENY (audience mismatch).

*Detection condition:*

if receipt.audience != expected_audience:
return DENY

*Binding defeated if removed:* audience binding (Section 5.7).

*Note:* The 0.4.1 implementation does not include audience; cross- executor receipt misdirection is not detectable at Level 0.

10.6. Key Substitution

*Scenario:* An attacker generates their own signing key, produces a forged receipt with a fraudulent verdict, and presents it along with the attacker's public key.

*Expected receipt change:* The receipt's issuer field identifies the attacker's key, which is not in the consumer's trust anchor store.

*Expected verdict:* DENY (untrusted key).

*Detection condition:*

if receipt.issuer not in trusted_issuers:
return DENY
if not verify_signature(receipt, trusted_public_keys[receipt.issuer]):
return DENY

*Binding defeated if removed:* issuer binding (Section 5.6).

*Note:* At Level 0 with HMAC, key substitution requires the attacker to know the shared secret. At Level 2+ with Ed25519, key substitution is detectable via the issuer/audience bindings.

10.7. Verifier/Runtime Collusion

*Scenario:* The agent runtime and the verifier are operated by the same entity. The verifier is configured to always return ALLOW, regardless of the command. The receipts are technically valid (correct HMAC, correct bindings) but the governance is meaningless.

*Expected receipt change:* No change to the receipt itself. The receipt is valid but the rule evaluation is trivially permissive.

*Expected verdict:* The receipt passes cryptographic verification, but the AEB SHOULD flag the verifier as Class C (self-declared) and apply additional scrutiny.

*Detection condition:*

if verifier.deny_rate < 0.001 and verifier.total_receipts > 10000:
flag_for_review(verifier)

*Mitigation:* This is not a cryptographic attack; it is a governance failure. Mitigation requires:

  • Independent auditing of the verifier's rule set (Class B).

  • Out-of-process deployment with the verifier operated by a different organization than the runtime (Class A, independent operator).

  • Statistical monitoring of verifier verdict distributions.

10.8. Missing Transport

*Scenario:* The verifier is configured for out-of-process deployment, but the gRPC transport is not implemented or is unavailable. The agent runtime falls back to allowing the tool invocation without verification.

*Expected receipt change:* No receipt is produced. The tool invocation proceeds without governance.

*Expected verdict:* This is a fail-open condition. A conforming implementation MUST block the tool invocation (fail-closed).

*Detection condition:*

try:
    result = await verifier_client.verify(command)
except ConnectionError:
    raise PermissionError("Verifier unreachable")

*Binding defeated if removed:* Fail-closed semantics (Section 7.1).

*Note:* The 0.4.1 reference implementation correctly implements fail- closed for in-process verification. The out-of-process transport has been implemented: the Unix-socket transport is tested in tests/test_unix_socket_security.py and TCP with TLS is tested in tests/test_tls_security.py. The fail-closed wrapper catches ConnectionError from the transport layer and blocks the invocation. However, a deployment that patches around the fail-closed wrapper would create a fail-open vulnerability.

11. Security Considerations

*Truncated hashes.* The 0.4.1 implementation truncates params_hash to 16 hex characters (64 bits) and receipt to 32 hex characters (128 bits). While sufficient for audit uniqueness within a single deployment, these truncation levels provide reduced collision resistance compared to full SHA-256 outputs. Implementations targeting cross-deployment interoperability SHOULD use full-length digests.

*HMAC key exposure in in-process mode.* When the verifier runs in the same process as the agent, a compromised agent can read the signing key from memory and forge receipts. Out-of-process deployment mitigates this; as of 0.4.1, the Unix-socket transport (tests/test_unix_socket_security.py) and TCP with TLS transport (tests/test_tls_security.py) are implemented and tested.

*Float timestamp precision.* The timestamp and verified_at fields use Python floats (IEEE 754 double precision). This provides approximately 15-17 significant decimal digits, which is sufficient for microsecond precision at current epoch values but MAY lose precision for comparisons between very close timestamps. Implementations SHOULD use monotonic clocks (time.perf_counter()) for latency measurement and wall clocks (time.time()) only for issuance timestamps.

*JSON canonicalization.* The params_hash and config_hash depend on deterministic JSON serialization. Any difference in serialization (different key ordering, different whitespace handling, different Unicode encoding) produces a different hash. Implementations MUST use the canonical serialization specified in Section 3.2 and Section 4.2.

*Rule evaluation ordering.* The rule_summary field records rules in evaluation order. Because DENY short-circuits evaluation, two receipts for the same command MAY have different rule_summary values if the rule set changes between invocations. The config_hash binding (Level 1+) addresses this by binding the receipt to the exact rule set.

*TOCTOU in out-of-process mode.* Between the time the verifier evaluates a command and the time the agent executes the tool, the runtime environment may change. The runtime_context_hash (Level 2) mitigates this by binding the receipt to the context at verification time; any subsequent context change invalidates the binding.

*Receipt chaining.* This specification does not define receipt chaining (each receipt is independent). Implementations that require ordered audit trails SHOULD use the sequence field (Section 5.8) or implement external chaining (e.g., hash-chain the receipts in the audit log).

12. IANA Considerations

This document does not request any IANA allocations.

13. References

13.1. Normative References

[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/info/rfc2119>.
[RFC7493]
Bray, T., Ed., "The I-JSON Message Format", RFC 7493, DOI 10.17487/RFC7493, , <https://www.rfc-editor.org/info/rfc7493>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/info/rfc8174>.
[RFC8785]
Rundgren, A., Jordan, B., and S. Erdtman, "JSON Canonicalization Scheme (JCS)", RFC 8785, DOI 10.17487/RFC8785, , <https://www.rfc-editor.org/info/rfc8785>.

13.2. Informative References

[CCS-FORMAL]
Wang, G., "CCS Formal Framework", DOI 10.5281/zenodo.21271910, , <https://doi.org/10.5281/zenodo.21271910>.
[CWE-636]
MITRE, M., "CWE-636: Not Failing Securely (Fail Open)", , <https://cwe.mitre.org/data/definitions/636.html>.
[I-D.schrock-action-evidence-boundary]
Schrock, I., "The Action Evidence Boundary for Consequential Agent Effects", Work in Progress, Internet-Draft, draft-schrock-action-evidence-boundary-03, , <https://datatracker.ietf.org/doc/html/draft-schrock-action-evidence-boundary-03>.
[I-D.schrock-ep-authorization-receipts]
Schrock, I., "Authorization Receipts for High-Risk Agent Actions", Work in Progress, Internet-Draft, draft-schrock-ep-authorization-receipts-09, , <https://datatracker.ietf.org/doc/html/draft-schrock-ep-authorization-receipts-09>.

Appendix A. CCS v1.2 Receipt Field Summary Table

+==+====================+=======+=====+===========+======+============+
|# |Field               |Type   |Level|Status     |Signed|Description |
+==+====================+=======+=====+===========+======+============+
|1 |trace_id            |16-char|0    |Implemented|Yes   |Unique event|
|  |                    |hex    |     |           |      |identifier  |
+--+--------------------+-------+-----+-----------+------+------------+

|2 |verdict             |enum   |0    |Implemented|Yes   |allow / deny|
|  |                    |string |     |           |      |/ escalate  |
+--+--------------------+-------+-----+-----------+------+------------+
|3 |timestamp           |float  |0    |Implemented|Yes   |Verification|
|  |                    |       |     |           |      |time        |
+--+--------------------+-------+-----+-----------+------+------------+
|4 |tool                |string |0    |Implemented|Yes   |Tool name   |
+--+--------------------+-------+-----+-----------+------+------------+
|5 |params_hash         |16-char|0    |Implemented|Yes   |SHA-256 of  |
|  |                    |hex    |     |           |      |params,     |
|  |                    |       |     |           |      |truncated   |
+--+--------------------+-------+-----+-----------+------+------------+
|6 |rule_summary        |string |0    |Implemented|Yes   |Pipe-       |
|  |                    |       |     |           |      |delimited   |
|  |                    |       |     |           |      |rule results|
+--+--------------------+-------+-----+-----------+------+------------+
|7 |receipt             |32-char|0    |Implemented|N/A   |HMAC-SHA256 |
|  |                    |hex    |     |           |      |signature   |
+--+--------------------+-------+-----+-----------+------+------------+
|8 |verified_at         |float  |0    |Implemented|No    |Verification|
|  |                    |       |     |           |      |timestamp   |
+--+--------------------+-------+-----+-----------+------+------------+
|9 |block_reason        |string |0    |Implemented|No    |Deny/       |
|  |                    |       |     |           |      |escalate    |
|  |                    |       |     |           |      |reason      |
+--+--------------------+-------+-----+-----------+------+------------+
|10|request_hash        |hex    |1    |Specified  |Yes   |SHA-256 of  |
|  |                    |string |     |           |      |full request|
+--+--------------------+-------+-----+-----------+------+------------+
|11|config_hash         |hex    |1    |Specified  |Yes   |SHA-256 of  |
|  |                    |string |     |           |      |canonical   |
|  |                    |       |     |           |      |config      |
+--+--------------------+-------+-----+-----------+------+------------+
|12|response_hash       |hex    |2    |Specified  |Post- |SHA-256 of  |
|  |                    |string |     |           |hoc   |response    |
+--+--------------------+-------+-----+-----------+------+------------+
|13|runtime_context_hash|hex    |2    |Specified  |Yes   |SHA-256 of  |
|  |                    |string |     |           |      |runtime     |
|  |                    |       |     |           |      |context     |
+--+--------------------+-------+-----+-----------+------+------------+
|14|action              |string |2    |Specified  |Yes   |CAID-       |
|  |                    |       |     |           |      |compatible  |
|  |                    |       |     |           |      |action ID   |
+--+--------------------+-------+-----+-----------+------+------------+
|15|issuer              |URI    |2    |Specified  |Yes   |Verifier    |
|  |                    |string |     |           |      |identifier  |
+--+--------------------+-------+-----+-----------+------+------------+
|16|audience            |URI    |2    |Specified  |Yes   |Intended    |
|  |                    |string |     |           |      |consumer    |
+--+--------------------+-------+-----+-----------+------+------------+
|17|nonce               |hex    |2    |Specified  |Yes   |Single-use  |
|  |                    |string |     |           |      |anti-replay |
+--+--------------------+-------+-----+-----------+------+------------+
|18|sequence            |integer|2    |Specified  |Yes   |Monotonic   |
|  |                    |       |     |           |      |counter     |
+--+--------------------+-------+-----+-----------+------+------------+
|19|issued_at           |float  |2    |Specified  |Yes   |Issue       |
|  |                    |       |     |           |      |timestamp   |
+--+--------------------+-------+-----+-----------+------+------------+
|20|expires_at          |float  |2    |Specified  |Yes   |Expiry      |
|  |                    |       |     |           |      |timestamp   |
+--+--------------------+-------+-----+-----------+------+------------+
|21|max_clock_skew      |float  |2    |Specified  |Yes   |Clock       |
|  |                    |       |     |           |      |tolerance   |
|  |                    |       |     |           |      |(seconds)   |
+--+--------------------+-------+-----+-----------+------+------------+
Figure 4

Appendix B. Conformance Test Vector Format

Each conformance test vector is encoded as a JSON object:

{
  "vector_id": "CV-001",
  "description": "Basic ALLOW receipt verification",
  "level": 0,
  "category": "positive",
  "input": {
    "command": {
      "agent_id": "test-agent",
      "tool": "search_web",
      "params": {"query": "weather in Tokyo"},
      "timestamp": 1722384000.0,
      "trace_id": "0000000000000001"
    },
    "rules": ["ssrf_protection", "rce_protection", "credential_leak"],
    "signing_key_hex": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
  },
  "expected": {
    "verdict": "allow",
    "block_reason": "",
    "receipt_valid": true,
    "rule_summary_pattern": "ssrf_protection=allow|rce_protection=allow|credential_leak=allow"
  },
  "negative_variant": null
}

For negative test vectors:

{
  "vector_id": "NV-001",
  "description": "Changed arguments detected by params_hash mismatch",
  "level": 0,
  "category": "negative",
  "attack": {
    "type": "changed_arguments",
    "modification": "params.query changed from 'weather in Tokyo' to 'weather in Osaka'"
  },
  "expected": {
    "detection_point": "params_hash mismatch",
    "verdict": "deny",
    "binding_defeated_if_removed": "params_hash (Section 5.5)"
  }
}

Author's Address

Guigui Wang
Correctover
Xiamen, Fujian
China