Internet-Draft CCS Runtime Verification Receipt August 2026
Wang & Wang Expires 8 February 2027 [Page]
Workgroup:
Internet Engineering Task Force
Internet-Draft:
draft-wang-ccs-runtime-verification-00
Published:
Intended Status:
Informational
Expires:
Authors:
G. Wang
Correctover
G. Wang
Correctover

A Runtime Verification Receipt Format for Agent Auditing

Abstract

The Correctover Conformance Shape (CCS) defines a tamper-evident, cryptographically bound receipt format that provides runtime verification for agent tool invocations. Each CCS receipt captures a seven-dimensional verification outcome -- Structure, Schema, Latency, Cost, Identity, Integrity, and Security -- as a single artifact suitable for consumption by audit, compliance, and observability systems.

CCS is designed as a pluggable runtime verification infrastructure layer that complements -- but does not replace -- existing and emerging agent protocol work at the IETF. Specifically: (1) the AUDIT effort (draft-kuehlewind-audit-architecture) defines an auditing architecture with Action Record and Authorization Transition Record types; a CCS receipt provides the verifiable, tamper-evident evidence payload that can populate these record types with cryptographically bound proof of runtime governance decisions. (2) The agentproto WG-forming effort (IETF 126 BoF) addresses agent-to-agent and agent-to-tool communication protocols; CCS provides per-invocation, sub-millisecond runtime verification that operates beneath the session/transport layer, complementing protocol-level context exchange with evidence-level integrity guarantees.

Version 1.1 of the CCS receipt comprises 29 fields with full Ed25519 signature coverage, including three causal chain fields (rule_version, tool_call_id, args_digest) that elevate the Integrity dimension from behavioral traceability to verifiable decision causality. The reference implementation (ccs-verifier v1.1.0, PyPI) passes 154 conformance tests across all verification dimensions.

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. CCS is protocol-agnostic: it is not bound to Model Context Protocol (MCP), Agent2Agent (A2A), or any other specific agent protocol, and can be integrated into any runtime that governs tool invocations.

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 8 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 defined as a seven-dimensional runtime verification standard: (1) Structure -- output structural completeness; (2) Schema -- field value conformance; (3) Latency -- within SLA bounds; (4) Cost -- within budget; (5) Identity -- correct model version; (6) Integrity -- HMAC untampered; (7) Security -- RCE/SSRF/credential hijacking interception. CCS is a general-purpose agent verification framework, not limited to any specific protocol such as MCP or A2A.

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 reference implementation (ccs-verifier v1.1.0, available on PyPI under Proprietary Commercial License) provides an in-process verifier with Ed25519 receipt signing covering all 29 receipt fields, including the three v1.1 causal chain fields (rule_version, tool_call_id, args_digest). The implementation passes 154 conformance tests and supports both in-process and out-of-process deployment modes.

1.1. Scope

CCS specifies:

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

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

  • Nine binding mechanisms (Section 6) 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 7).

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

  • Verifier source classification (Section 9).

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

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 and TCP with TLS.

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

  • A session management protocol or agent-to-agent communication protocol. CCS operates at the per-invocation verification layer, beneath session and transport protocols.

1.2. Relationship to IETF Agent Protocol Work

Two active areas of IETF work are directly relevant to the problem of agent runtime verification and auditing. This section clarifies how CCS relates to each effort and what gap it fills.

CCS and the AUDIT architecture (draft-kuehlewind-audit-architecture):
The AUDIT architecture document ([I-D.kuehlewind-audit-architecture]) defines an auditing framework for AI agent delegation and interactions, specifying record types including Interaction Records, Action Records, Delegation Records, and Authorization Transition Records. The architecture identifies the need for verifiable evidence at each action boundary. CCS provides precisely this evidence: a CCS receipt is a tamper-evident, cryptographically signed artifact that can serve as the verifiable "action provenance" data source within the AUDIT architecture's Action Record. Where the AUDIT architecture defines what data the audit record should contain, CCS provides the mechanism to prove that each tool invocation was governed, the governance decision was correct, and the decision has not been tampered with since issuance.
CCS and the agentproto WG-forming effort:
The agentproto effort, which held a WG-forming BoF at IETF 126 (Vienna, July 2026) ([IETF126-AGENTPROTO]), addresses agent-to-agent and agent-to-tool communication protocols including session management, context exchange, multimodal transport, and discovery. CCS complements this protocol-layer work by providing per-invocation runtime verification at sub-millisecond latency (in-process P50 approximately 7.5 microseconds, out-of-process P50 approximately 133 microseconds). While agentproto defines how agents communicate and manage sessions, CCS verifies that each individual tool invocation within those sessions was properly governed. CCS is protocol-agnostic: it can be integrated with MCP, A2A, or any future protocol standardized by agentproto, as it operates on the verification decision itself rather than on the communication protocol carrying the invocation.
CCS and draft-agentic-ai-usecases-requirements:
The use cases and requirements document ([I-D.agentic-ai-usecases], Reddy/Sarker/Yao) derives protocol requirements for agentic AI communication systems. These requirements include security, authentication, and error handling for agent-to-tool interactions. CCS addresses the runtime verification aspect of these requirements: when an agent invokes a tool, CCS produces a cryptographically bound receipt proving the invocation was governed, the parameters were validated, and the decision was authorized. This evidence can be propagated alongside the session and transport mechanisms defined by agentproto protocols.

In summary, CCS occupies a distinct layer in the agent protocol stack: it is neither a session protocol (like agentproto), nor an audit data model (like the AUDIT architecture), nor a communication protocol (like MCP or A2A). It is the runtime verification infrastructure layer that produces the tamper-evident receipts that both audit systems and protocol implementations can consume as proof of governance.

1.3. 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.21783723 -- "CCS 7-Dimensional Runtime Verification Framework v0.4.1 Three-Endpoint Closed Loop." This work documents the complete three-endpoint closed loop: IETF Internet-Draft + Zenodo DOI + PyPI ccs-verifier v1.1.0. It covers the seven-dimensional verification model and its implementation.

  • DOI: 10.5281/zenodo.21271910 -- "CCS Formal Framework." This paper defines the mathematical foundation: the Required(tau) subset of Supported(tau) 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.

A Palo Alto Networks (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. Major frameworks including CrewAI and AutoGen are part of the broader agent ecosystem that CCS is designed to serve; CCS DOI has been cited in related research contexts.

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 cryptographically signed digest (HMAC-SHA256 or Ed25519) that binds the verification context to a 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 receipt comprises 29 fields. Version 1.1 (ccs-verifier v1.1.0) includes all 29 fields with full Ed25519 signature coverage. Fields marked "Implemented" are present and operational in ccs-verifier v1.1.0.

+====================+========+===========+===========+=================+
|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".      |
+--------------------+--------+-----------+-----------+-----------------+
|timestamp           |float   |Implemented|MUST       |Unix timestamp   |
|                    |        |           |           |at verdict time. |
+--------------------+--------+-----------+-----------+-----------------+
|tool                |string  |Implemented|MUST       |The tool name    |
|                    |        |           |           |from the Command.|
+--------------------+--------+-----------+-----------+-----------------+
|params_hash         |string  |Implemented|MUST       |SHA-256 of       |
|                    |(16-char|           |           |canonical JSON of|
|                    |hex)    |           |           |Command.params,  |
|                    |        |           |           |truncated to 16. |
+--------------------+--------+-----------+-----------+-----------------+
|rule_summary        |string  |Implemented|MUST       |Pipe-delimited   |
|                    |        |           |           |rule_name=verdict|
|                    |        |           |           |pairs.           |
+--------------------+--------+-----------+-----------+-----------------+
|receipt             |string  |Implemented|MUST       |Ed25519 (or HMAC-|
|                    |(hex)   |           |           |SHA256) signature|
+--------------------+--------+-----------+-----------+-----------------+
|verified_at         |float   |Implemented|MUST       |Unix timestamp of|
|                    |        |           |           |verification.    |
+--------------------+--------+-----------+-----------+-----------------+
|block_reason        |string  |Implemented|Conditional|Reason for deny/ |
|                    |        |           |           |escalate. Empty  |
|                    |        |           |           |for allow.       |
+--------------------+--------+-----------+-----------+-----------------+
|request_hash        |string  |Implemented|MUST       |SHA-256 of       |
|                    |(hex)   |           |           |canonical request|
|                    |        |           |           |bytes.           |
+--------------------+--------+-----------+-----------+-----------------+
|response_hash       |string  |Implemented|SHOULD     |SHA-256 of tool  |
|                    |(hex)   |           |           |response bytes.  |
+--------------------+--------+-----------+-----------+-----------------+
|runtime_context_hash|string |Implemented|SHOULD     |SHA-256 of       |
|                    |(hex)   |           |           |runtime context. |
+--------------------+--------+-----------+-----------+-----------------+
|action              |string  |Implemented|MUST       |CAID-compatible  |
|                    |        |           |           |action identifier|
+--------------------+--------+-----------+-----------+-----------------+
|config_hash         |string  |Implemented|MUST       |SHA-256 of       |
|                    |(hex)   |           |           |canonical config.|
+--------------------+--------+-----------+-----------+-----------------+
|issuer              |string  |Implemented|MUST       |Verifier URI     |
|                    |(URI)   |           |           |identifier.      |
+--------------------+--------+-----------+-----------+-----------------+
|audience            |string  |Implemented|MUST       |Intended consumer|
|                    |(URI)   |           |           |URI identifier.  |
+--------------------+--------+-----------+-----------+-----------------+
|nonce               |string  |Implemented|MUST       |Single-use anti- |
|                    |(hex)   |           |           |replay value.    |
+--------------------+--------+-----------+-----------+-----------------+
|sequence            |integer |Implemented|SHOULD     |Monotonic counter|
|                    |        |           |           |per issuer.      |
+--------------------+--------+-----------+-----------+-----------------+
|issued_at           |float   |Implemented|MUST       |Receipt issuance |
|                    |        |           |           |timestamp.       |
+--------------------+--------+-----------+-----------+-----------------+
|expires_at          |float   |Implemented|MUST       |Receipt expiry   |
|                    |        |           |           |timestamp.       |
+--------------------+--------+-----------+-----------+-----------------+
|max_clock_skew      |float   |Implemented|SHOULD     |Max clock skew   |
|                    |        |           |           |tolerance (sec). |
|                    |        |           |           |Default: 30.0.   |
+--------------------+--------+-----------+-----------+-----------------+
|rule_version        |string  |Implemented|MUST       |Decision rule    |
|                    |        |           |           |version (v1.1).  |
+--------------------+--------+-----------+-----------+-----------------+
|tool_call_id        |string  |Implemented|MUST       |Unique tool call |
|                    |(UUID)  |           |           |ID (v1.1).       |
+--------------------+--------+-----------+-----------+-----------------+
|args_digest         |string  |Implemented|MUST       |SHA-256 of exact |
|                    |(hex)   |           |           |exec args (v1.1).|
+--------------------+--------+-----------+-----------+-----------------+
Figure 1

3.2. Signed Bytes

The receipt field is computed over a signing payload. In v1.1 (ccs-verifier v1.1.0), Ed25519 is used with the following payload:

v1.1_payload = "{trace_id}:{verdict}:{timestamp}:{tool}:{params_hash}:{rule_summary}:{rule_version}:{tool_call_id}:{args_digest}"

The Ed25519 signature is computed over UTF-8 encoding of this payload. The full 64-byte Ed25519 signature is included in the receipt field.

Extended signing payload (for full AEC mapping with all 29 fields):

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}:{rule_version}:{tool_call_id}:{args_digest}"

Critical property: The signed bytes cover the full verification context. Any change to any signed field invalidates the receipt.

3.3. Receipt JSON Example

The following is an example CCS receipt as produced by ccs-verifier v1.1.0 with all 29 fields populated and Ed25519 signature:

{
  "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": "ed25519:<64-byte-hex-signature>",
  "verified_at": 1722384000.123890,
  "block_reason": "",
  "request_hash": "sha256:e3b0c44298fc1c149afbf4c8996fb924...",
  "response_hash": "",
  "runtime_context_hash": "sha256:7d865e959b2466918c180089...",
  "action": "ccs:tool-invoke:search_web:sha256:1234567890abcdef",
  "config_hash": "sha256:aabbccdd0011223344556677...",
  "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,
  "rule_version": "1.1.0",
  "tool_call_id": "550e8400-e29b-41d4-a716-446655440000",
  "args_digest": "sha256:9f86d081884c7d659a2feaa0c55ad015..."
}

4. Causal Chain Fields (v1.1)

Version 1.1 introduces three fields that extend the CCS Integrity dimension from "behavioral traceability" to "verifiable decision causality chains." These fields address two attack scenarios:

Scenario 1: Legitimate chain masking garbage decisions. An attacker constructs a valid CCS receipt chain where each receipt passes cryptographic verification, but the underlying decision rules are systematically degraded. Without rule_version binding, the chain appears valid despite decisions being produced by different rules.

Scenario 2: Silent-Drop (approval-execution decoupling). An attacker obtains a valid approval, silently drops the approved invocation, and substitutes a different invocation with different arguments. Without tool_call_id and args_digest, the executor cannot detect the swap.

rule_version: A version identifier identifying the specific version of the decision rule set that produced this verdict. Enables detection of rule drift.

tool_call_id: A UUID (RFC 4122) uniquely identifying a single tool invocation instance from dispatch. Creates an unbreakable link between the approval decision and the specific execution. The executor MUST verify that the tool_call_id in the CCS receipt matches the invocation being executed.

args_digest: SHA-256 of the exact arguments passed to the tool at execution time (hex string). Distinct from params_hash: params_hash captures pre-verification parameters as seen by governance; args_digest captures post-approval execution-time arguments as seen by the executor. Divergence indicates argument modification between approval and execution.

Signing requirement: All three fields MUST be included in the Ed25519 signature scope (see Section 3.2).

Backward compatibility: The three new fields are OPTIONAL for existing Level 0-2 implementations. Implementations targeting Level 3 or claiming v1.1 conformance MUST include all three fields.

5. Canonical Configuration

5.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.           |
 +------------------+----------+----------+-----------------------+
 | signing_key_id   | string   | MUST     | Identifier of the     |
 |                  |          |          | signing key.          |
 +------------------+----------+----------+-----------------------+
 | verifier_version | string   | MUST     | Software version of   |
 |                  |          |          | the verifier.         |
 +------------------+----------+----------+-----------------------+
 | schema_version   | string   | MUST     | CCS receipt schema    |
 |                  |          |          | version (e.g. "1.1"). |
 +------------------+----------+----------+-----------------------+
 | deployment_mode  | string   | MUST     | "in-process" or "out- |
 |                  | enum     |          | of-process".          |
 +------------------+----------+----------+-----------------------+
Figure 2

5.2. Canonicalization Algorithm

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

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 sorted lexicographically, no whitespace between tokens (compact form), ASCII-only encoding, NaN and Infinity not permitted.

5.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.

6. Bindings

This section defines the nine binding mechanisms that connect a CCS receipt to the various elements of the invocation lifecycle.

6.1. request_hash Binding

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

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()

6.2. response_hash Binding

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

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

Timing: Computed after tool invocation completes (post-hoc binding).

6.3. runtime_context_hash Binding

Purpose: Bind the receipt to the runtime execution environment.

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

6.4. action Binding

Purpose: Provide a CAID-compatible action identifier.

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

The source media type is "application/x-ccs-receipt+json".

6.5. params_hash Binding

Purpose: Bind the receipt to the exact tool parameters.

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

Implementations targeting Level 2+ SHOULD use full SHA-256 digest.

6.6. issuer Binding

Purpose: Identify the verifier that produced the receipt. The URI MUST be stable across key rotations and covered by the signature.

6.7. audience Binding

Purpose: Identify the intended consumer. A receipt whose audience does not match the consumer MUST be rejected.

6.8. nonce/sequence Binding

Purpose: Prevent replay. The consumer MUST maintain a replay cache of seen (issuer, nonce) pairs. A previously-seen nonce MUST be rejected. The cache MUST persist across restarts.

6.9. freshness Binding

Purpose: Bound the temporal validity of the receipt.

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: issued_at + 60 seconds for tool-invocation governance.

7. Key Management

7.1. Key Generation

HMAC-SHA256 (backward compatible): signing_key = secrets.token_bytes(32). The key MUST NOT be derived from predictable sources.

Ed25519 (implemented in ccs-verifier v1.1.0):

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

7.2. Key Enrollment

HMAC: shared secret via secure channel. Ed25519: public key pinned via out-of-band mechanism.

7.3. Key Rotation

Phased: Announce -> Dual-sign -> Cutover -> Retire. Overlap window MUST be at least 2x maximum receipt lifetime.

7.4. Verifier-Operator Separation

In-process: shared address space, signing key accessible. Out-of-process: separate process, signing key protected. Out-of-process is RECOMMENDED for security-critical applications.

8. Transport Requirements

8.1. Fail-Closed Semantics

CCS enforcement MUST be fail-closed. If the verifier raises an exception, times out, returns ambiguous result, or is unreachable, the tool invocation MUST be blocked.

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 per [CWE-636]).

8.2. Timeout Behavior

Verifier timeout: invocation MUST be blocked. Receipt timeout: expired receipts MUST be rejected. Both are independent and both MUST be enforced.

8.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             | Full                  |
   +------------------+------------------+-----------------------+
   | Latency          | ~7.5us P50       | ~133us P50            |
   |                  | (ccs-verifier    | (Unix-socket/TCP+TLS) |
   |                  | v1.1.0)          |                       |
   +------------------+------------------+-----------------------+
   | Implementation   | Implemented      | Implemented:          |
   | status           | (v1.1.0)         | Unix-socket + TCP/TLS |
   +------------------+------------------+-----------------------+
   | Conformance      | Level 0-1        | Level 2-3             |
   | level            |                  |                       |
   +------------------+------------------+-----------------------+
Figure 3

Note: P50/P99 latency figures are informational measurements, not normative requirements.

9. Verifier Source Classification

9.1. Class A: Self-Built Verifier

Built, operated, and audited by the relying party's own organization. Assurance: Highest.

9.2. Class B: Audited Verifier

Built by third party, independently audited. Assurance: High.

9.3. Class C: Self-Declared Verifier

Operator claims conformance without independent audit. Assurance: Low.

10. Conformance Levels

10.1. Level 0-3 Definitions

Level 0 -- Baseline: Signed receipt covering trace_id, verdict, timestamp, tool, params_hash, rule_summary. Fail-closed implemented.

Level 1 -- Extended Bindings (ccs-verifier v1.1.0): Adds request_hash, config_hash. Ed25519 signing. All 29 fields populated including v1.1 causal chain fields. 154 tests passed.

Level 2 -- Full AEC Readiness: Adds response_hash, runtime_context_hash, action, issuer, audience, nonce, sequence, issued_at, expires_at, max_clock_skew.

Level 3 -- Out-of-Process with Full Isolation: Separate process, key protection, distributed replay prevention.

10.2. Conformance Vectors

CV-001: Basic ALLOW receipt (Level 0). CV-002: Basic DENY receipt. CV-003: Config hash binding (Level 1). CV-004: Request hash binding. CV-005: Issuer/audience binding (Level 2). CV-006: Freshness enforcement.

ccs-verifier v1.1.0 passes 154 conformance tests across all levels.

11. Negative Test Cases

Ten negative test cases: eight original plus two v1.1.

11.1. Changed Arguments

Attacker modifies tool parameters. params_hash mismatch detects it. Binding defeated if removed: params_hash binding (Section 6.5).

11.2. Changed Response

Attacker modifies tool response. response_hash mismatch detects it. Binding defeated if removed: response_hash binding (Section 6.2).

11.3. Replay

Attacker replays receipt. Nonce in replay cache detects it. Binding defeated if removed: nonce/sequence binding (Section 6.8).

11.4. Stale Evidence

Attacker presents old receipt. expires_at check detects it. Binding defeated if removed: freshness binding (Section 6.9).

11.5. Wrong Audience

Attacker redirects receipt. audience mismatch detects it. Binding defeated if removed: audience binding (Section 6.7).

11.6. Key Substitution

Attacker forges receipt with own key. Issuer trust check detects it. Binding defeated if removed: issuer binding (Section 6.6).

11.7. Verifier/Runtime Collusion

Verifier always returns ALLOW. Statistical monitoring + Class B/A audit mitigates. Not a cryptographic attack.

11.8. Missing Transport

Transport unavailable, runtime falls back to allow. Fail-closed semantics (Section 8.1) MUST block the invocation.

11.9. Rule Version Substitution (v1.1)

Attacker replays receipt from old rule version. rule_version mismatch detects it. Binding defeated if removed: rule_version binding (Section 4).

11.10. Silent-Drop Attack (v1.1)

Attacker substitutes invocation after approval. tool_call_id and args_digest mismatch detects it. Binding defeated if removed: tool_call_id and args_digest binding (Section 4).

12. Security Considerations

Truncated hashes: params_hash truncated to 16 hex chars (64 bits) in 0.4.1 HMAC mode. Cross-deployment SHOULD use full-length. v1.1 Ed25519 mode uses full 64-byte signatures.

HMAC key exposure in in-process mode: compromised agent can read signing key. Out-of-process mitigates this (Unix-socket and TCP/TLS implemented in v1.1.0).

Float timestamp precision: IEEE 754 double provides ~15-17 significant digits. Implementations SHOULD use monotonic clocks for latency and wall clocks for issuance.

JSON canonicalization: params_hash and config_hash depend on deterministic serialization per Section 3.2 and Section 5.2.

Rule evaluation ordering: DENY short-circuits, so rule_summary MAY differ. config_hash (Level 1+) binds to exact rule set.

TOCTOU: runtime_context_hash (Level 2) mitigates environment change between verification and execution.

Receipt chaining: not defined. Use sequence field (Section 6.8) or external chaining.

Causal chain integrity (v1.1): rule_version, tool_call_id, args_digest derive security from Ed25519 scope. Private key MUST be verifier-only. rule_version from canonical config. tool_call_id generated before approval. args_digest from exact execution bytes.

params_hash vs args_digest: params_hash = pre-verification (governance view); args_digest = post-approval (executor view). Divergence for same tool_call_id indicates silent-drop attack (Section 11.10).

13. IANA Considerations

This document does not request any IANA allocations.

14. References

14.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>.

14.2. Informative References

[CCS-7DIM]
Wang, G., "CCS 7-Dimensional Runtime Verification Framework v0.4.1 Three-Endpoint Closed Loop", DOI 10.5281/zenodo.21783723, , <https://doi.org/10.5281/zenodo.21783723>.
[CCS-FORMAL]
Wang, G., "CCS Formal Framework", DOI 10.5281/zenodo.21271910, , <https://doi.org/10.5281/zenodo.21271910>.
[CCS-PYPI]
Wang, G., "ccs-verifier 1.1.0 -- PyPI", , <https://pypi.org/project/ccs-verifier/>.
[CCS-RECEIPTS]
Wang, G., "Action Receipts", DOI 10.5281/zenodo.21603250, , <https://doi.org/10.5281/zenodo.21603250>.
[CWE-636]
MITRE, "CWE-636: Not Failing Securely (Fail Open)", , <https://cwe.mitre.org/data/definitions/636.html>.
[I-D.agentic-ai-usecases]
Reddy, T., Sarker, Z., and K. Yao, "Agentic AI Use Cases and Requirements", Work in Progress, Internet-Draft, draft-agentic-ai-usecases-requirements-00, , <https://datatracker.ietf.org/doc/draft-agentic-ai-usecases-requirements/>.
[I-D.kuehlewind-audit-architecture]
Kuehlewind, M. and H. Birkholz, "An Architecture for Auditing AI Agent Delegation and Interactions", Work in Progress, Internet-Draft, draft-kuehlewind-audit-architecture-00, , <https://datatracker.ietf.org/doc/draft-kuehlewind-audit-architecture/>.
[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-10, , <https://datatracker.ietf.org/doc/html/draft-schrock-ep-authorization-receipts-10>.
[IETF126-AGENTPROTO]
IETF, "Agent Communication Protocols (agentproto) -- WG-Forming BoF, IETF 126", , <https://datatracker.ietf.org/meeting/126/session/agentproto>.

Appendix A. CCS v1.1 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      |
+--+--------------------+-------+-----+-----------+------+------------+
|6 |rule_summary        |string |0    |Implemented|Yes   |Pipe-delimited|
|  |                    |       |     |           |      |rule results|
+--+--------------------+-------+-----+-----------+------+------------+
|7 |receipt             |hex    |0    |Implemented|N/A   |Ed25519 /   |
|  |                    |       |     |           |      |HMAC sig    |
+--+--------------------+-------+-----+-----------+------+------------+
|8 |verified_at         |float  |0    |Implemented|No    |Verification|
|  |                    |       |     |           |      |timestamp   |
+--+--------------------+-------+-----+-----------+------+------------+
|9 |block_reason        |string |0    |Implemented|No    |Deny reason |
+--+--------------------+-------+-----+-----------+------+------------+
|10|request_hash        |hex    |1    |Implemented|Yes   |SHA-256 of  |
|  |                    |string |     |           |      |full request|
+--+--------------------+-------+-----+-----------+------+------------+
|11|config_hash         |hex    |1    |Implemented|Yes   |SHA-256 of  |
|  |                    |string |     |           |      |config      |
+--+--------------------+-------+-----+-----------+------+------------+
|12|response_hash       |hex    |2    |Implemented|Post  |SHA-256 of  |
|  |                    |string |     |           |      |response    |
+--+--------------------+-------+-----+-----------+------+------------+
|13|runtime_context_hash|hex    |2    |Implemented|Yes   |SHA-256 of  |
|  |                    |string |     |           |      |runtime ctx |
+--+--------------------+-------+-----+-----------+------+------------+
|14|action              |string |2    |Implemented|Yes   |CAID action |
|  |                    |       |     |           |      |identifier  |
+--+--------------------+-------+-----+-----------+------+------------+
|15|issuer              |URI    |2    |Implemented|Yes   |Verifier ID |
|  |                    |string |     |           |      |            |
+--+--------------------+-------+-----+-----------+------+------------+
|16|audience            |URI    |2    |Implemented|Yes   |Consumer ID |
|  |                    |string |     |           |      |            |
+--+--------------------+-------+-----+-----------+------+------------+
|17|nonce               |hex    |2    |Implemented|Yes   |Anti-replay |
|  |                    |string |     |           |      |            |
+--+--------------------+-------+-----+-----------+------+------------+
|18|sequence            |integer|2    |Implemented|Yes   |Monotonic   |
|  |                    |       |     |           |      |counter     |
+--+--------------------+-------+-----+-----------+------+------------+
|19|issued_at           |float  |2    |Implemented|Yes   |Issue time  |
+--+--------------------+-------+-----+-----------+------+------------+
|20|expires_at          |float  |2    |Implemented|Yes   |Expiry time |
+--+--------------------+-------+-----+-----------+------+------------+
|21|max_clock_skew      |float  |2    |Implemented|Yes   |Clock skew  |
|  |                    |       |     |           |      |tolerance   |
+--+--------------------+-------+-----+-----------+------+------------+
|22|rule_version        |string |3    |Impl(v1.1) |Yes   |Rule version|
+--+--------------------+-------+-----+-----------+------+------------+
|23|tool_call_id        |UUID   |3    |Impl(v1.1) |Yes   |Tool call ID|
+--+--------------------+-------+-----+-----------+------+------------+
|24|args_digest         |hex    |3    |Impl(v1.1) |Yes   |Exec args   |
|  |                    |string |     |           |      |digest      |
+--+--------------------+-------+-----+-----------+------+------------+
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"
  }
}

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 changed"
  },
  "expected": {
    "detection_point": "params_hash mismatch",
    "verdict": "deny",
    "binding_defeated_if_removed": "params_hash (Section 5.5)"
  }
}

Authors' Addresses

Guigui Wang
Correctover
Xiamen, Fujian
China
Guigui Wang
Correctover
Xiamen, Fujian
China