Correctover Conformance Shape (CCS): A Receipt and Binding Specification for Agent Runtime Verification
draft-correctover-ccs-02
This document is an Internet-Draft (I-D).
Anyone may submit an I-D to the IETF.
This I-D is not endorsed by the IETF and has no formal standing in the
IETF standards process.
| Document | Type | Active Internet-Draft (individual) | |
|---|---|---|---|
| Author | Correctover | ||
| Last updated | 2026-08-09 | ||
| RFC stream | (None) | ||
| Intended RFC status | (None) | ||
| Formats | |||
| Stream | Stream state | (No stream defined) | |
| Consensus boilerplate | Unknown | ||
| RFC Editor Note | (None) | ||
| IESG | IESG state | I-D Exists | |
| Telechat date | (None) | ||
| Responsible AD | (None) | ||
| Send notices to | (None) |
draft-correctover-ccs-02
Internet Engineering Task Force G. Wang
Internet-Draft Correctover
Intended status: Informational 10 August 2026
Expires: 10 February 2027
Correctover Conformance Shape (CCS): A Receipt and Binding Specification
for Agent Runtime Verification
draft-correctover-ccs-02
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 10 February 2027.
Copyright Notice
Copyright (c) 2026 IETF Trust and the persons identified as the
document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents
(https://trustee.ietf.org/license-info) in effect on the date of
publication of this document. Please review these documents
carefully, as they describe your rights and restrictions with
respect to this document. Code Components extracted from this
document must include Revised BSD License text as described in
Section 4.e of the Trust Legal Provisions and are provided
without warranty as described in the Revised BSD License.
Table of Contents
Wang Expires 10 February 2027 [Page 1]
Internet-Draft CCS Receipt and Binding Specification August 2026
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1. Scope . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2. Relationship to CCS Formal Framework (DOI References) . . 3
2. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 4
3. CCS Receipt Schema . . . . . . . . . . . . . . . . . . . . . . 5
3.1. Field Definitions . . . . . . . . . . . . . . . . . . . . 5
3.2. Signed Bytes . . . . . . . . . . . . . . . . . . . . . . . 8
3.3. Receipt JSON Example . . . . . . . . . . . . . . . . . . . 9
3.4. Verifier Policy Floor . . . . . . . . . . . . . . . . . . 10
3.5. Verification Outcome States . . . . . . . . . . . . . . . 11
4. Canonical Configuration . . . . . . . . . . . . . . . . . . . 12
4.1. Canonical Config Fields . . . . . . . . . . . . . . . . . 12
4.2. Canonicalization Algorithm . . . . . . . . . . . . . . . 13
4.3. Config Hash . . . . . . . . . . . . . . . . . . . . . . . 13
5. Bindings . . . . . . . . . . . . . . . . . . . . . . . . . . 13
5.1. request_hash Binding . . . . . . . . . . . . . . . . . . 13
5.2. response_hash Binding . . . . . . . . . . . . . . . . . . 14
5.3. runtime_context_hash Binding . . . . . . . . . . . . . . 14
5.4. action Binding . . . . . . . . . . . . . . . . . . . . . 15
5.5. params_hash Binding . . . . . . . . . . . . . . . . . . . 15
5.6. issuer Binding . . . . . . . . . . . . . . . . . . . . . 16
5.7. audience Binding . . . . . . . . . . . . . . . . . . . . 16
5.8. nonce/sequence Binding . . . . . . . . . . . . . . . . . 16
5.9. freshness Binding (issued_at + expires_at +
max_clock_skew) . . . . . . . . . . . . . . . . . . . . . 16
5.10. Receipt Time-Binding . . . . . . . . . . . . . . . . . . 17
6. Key Management . . . . . . . . . . . . . . . . . . . . . . . 17
6.1. Key Generation . . . . . . . . . . . . . . . . . . . . . 18
6.2. Key Enrollment . . . . . . . . . . . . . . . . . . . . . 18
6.3. Key Rotation . . . . . . . . . . . . . . . . . . . . . . 18
6.4. Verifier-Operator Separation . . . . . . . . . . . . . . 18
7. Transport Requirements . . . . . . . . . . . . . . . . . . . 19
7.1. Fail-Closed Semantics . . . . . . . . . . . . . . . . . . 19
7.2. Timeout Behavior . . . . . . . . . . . . . . . . . . . . 19
7.3. In-Process vs Out-of-Process Deployment . . . . . . . . . 19
8. Verifier Source Classification . . . . . . . . . . . . . . . 20
8.1. Class A: Self-Built Verifier . . . . . . . . . . . . . . 20
8.2. Class B: Audited Verifier . . . . . . . . . . . . . . . . 21
8.3. Class C: Self-Declared Verifier . . . . . . . . . . . . . 21
9. Conformance Levels . . . . . . . . . . . . . . . . . . . . . 21
9.1. Level 0-3 Definitions . . . . . . . . . . . . . . . . . . 21
9.2. Conformance Vectors (Positive Test Cases) . . . . . . . . 22
10. Negative Test Cases . . . . . . . . . . . . . . . . . . . . . 23
10.1. Changed Arguments . . . . . . . . . . . . . . . . . . . 23
10.2. Changed Response . . . . . . . . . . . . . . . . . . . . 23
10.3. Replay . . . . . . . . . . . . . . . . . . . . . . . . . 24
10.4. Stale Evidence . . . . . . . . . . . . . . . . . . . . . 24
Wang Expires 10 February 2027 [Page 2]
Internet-Draft CCS Receipt and Binding Specification August 2026
10.5. Wrong Audience . . . . . . . . . . . . . . . . . . . . . 24
10.6. Key Substitution . . . . . . . . . . . . . . . . . . . . 25
10.7. Verifier/Runtime Collusion . . . . . . . . . . . . . . . 25
10.8. Missing Transport . . . . . . . . . . . . . . . . . . . 25
11. Security Considerations . . . . . . . . . . . . . . . . . . . 26
12. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 27
13. References . . . . . . . . . . . . . . . . . . . . . . . . . 27
13.1. Normative References . . . . . . . . . . . . . . . . . . 27
13.2. Informative References . . . . . . . . . . . . . . . . . 28
Appendix A. CCS v1.2 Receipt Field Summary Table . . . . . . . . 28
Appendix B. Conformance Test Vector Format . . . . . . . . . . . 30
Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 31
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1. Scope . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2. Relationship to CCS Formal Framework (DOI References) . . 5
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
Wang Expires 10 February 2027 [Page 3]
Internet-Draft CCS Receipt and Binding Specification August 2026
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(T) subset of
Supported(T) 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,
model (Structure, Schema, Latency, Cost, Identity, Integrity,
Security).
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.
* *DOI: 10.5281/zenodo.21783723* -- "CCS 7-Dimensional Framework
Three-Endpoint Closed Loop." Contains: IETF Internet-Draft +
Wang Expires 10 February 2027 [Page 4]
Internet-Draft CCS Receipt and Binding Specification August 2026
Zenodo DOI + PyPI ccs-verifier v1.1.0. Seven-dimensional
verification model (Structure, Schema, Latency, Cost, Identity,
Integrity, Security). This record consolidates the protocol
specification, formal framework, and reference implementation
into a single verifiable package.
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.
*Outcome status*: The epistemic state of a verification result regarding
the action's outcome. One of: confirmed, dispatched, indeterminate.
Orthogonal to the verdict (allow/deny/escalate).
*Verifier policy floor*: The minimum security requirements enforced by a
CCS verifier, regardless of the server's self-declared profile. Non-
negotiable from the server side.
*Reconcilability*: The property of an action whereby the effecting side
Wang Expires 10 February 2027 [Page 5]
Internet-Draft CCS Receipt and Binding Specification August 2026
can attest to what actually occurred after execution. Independent from
severity.
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. All 22 fields
are implemented in ccs-verifier 0.4.1.
+====================+========+===========+===========+=================+
|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 |
Wang Expires 10 February 2027 [Page 6]
Internet-Draft CCS Receipt and Binding Specification August 2026
| | | | |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 |Implemented|MUST |SHA-256 of the |
| |(hex) | | |canonical bytes |
| | | | |of the original |
| | | | |request as |
| | | | |received by the |
| | | | |verifier. Binds |
| | | | |receipt to exact |
| | | | |request bytes |
| | | | |(Section 5.1). |
+--------------------+--------+-----------+-----------+-----------------+
|response_hash |string |Implemented|SHOULD |SHA-256 of the |
| |(hex) | | |tool response |
| | | | |bytes, computed |
| | | | |after invocation.|
| | | | |Binds receipt to |
| | | | |exact response |
| | | | |(Section 5.2). |
+--------------------+--------+-----------+-----------+-----------------+
|runtime_context_hash|string |Implemented|SHOULD |SHA-256 of |
Wang Expires 10 February 2027 [Page 7]
Internet-Draft CCS Receipt and Binding Specification August 2026
| |(hex) | | |canonical JSON of|
| | | | |runtime context |
| | | | |(caller identity,|
| | | | |tenant, |
| | | | |environment). |
| | | | |Binds receipt to |
| | | | |execution |
| | | | |environment |
| | | | |(Section 5.3). |
+--------------------+--------+-----------+-----------+-----------------+
|action |string |Implemented|MUST |The CAID- |
| | | | |compatible action|
| | | | |identifier for |
| | | | |this invocation. |
| | | | |14 enum values. |
| | | | |Enables AEC |
| | | | |matching |
| | | | |(Section 5.4). |
+--------------------+--------+-----------+-----------+-----------------+
|config_hash |string |Implemented|MUST |SHA-256 of the |
| |(hex) | | |canonical |
| | | | |configuration |
| | | | |(Section 4). |
| | | | |Binds receipt to |
| | | | |exact rule set. |
+--------------------+--------+-----------+-----------+-----------------+
|issuer |string |Implemented|MUST |Identifier of the|
| |(URI) | | |verifier that |
| | | | |produced this |
| | | | |receipt |
| | | | |(Section 5.6). |
+--------------------+--------+-----------+-----------+-----------------+
|audience |string |Implemented|MUST |Identifier of the|
| |(URI) | | |intended consumer|
| | | | |of this receipt |
| | | | |(Section 5.7). |
+--------------------+--------+-----------+-----------+-----------------+
|nonce |string |Implemented|MUST |Unpredictable, |
| |(hex) | | |single-use value |
| | | | |for replay |
| | | | |prevention |
| | | | |(Section 5.8). |
| | | | |UUID4-based. |
+--------------------+--------+-----------+-----------+-----------------+
|sequence |integer |Implemented|SHOULD |Monotonically |
| | | | |increasing |
| | | | |counter per |
| | | | |issuer for |
Wang Expires 10 February 2027 [Page 8]
Internet-Draft CCS Receipt and Binding Specification August 2026
| | | | |ordering |
| | | | |(Section 5.8). |
+--------------------+--------+-----------+-----------+-----------------+
|issued_at |float |Implemented|MUST |Unix timestamp |
| | | | |when the receipt |
| | | | |was issued |
| | | | |(distinct from |
| | | | |timestamp). |
| | | | |(Section 5.9). |
+--------------------+--------+-----------+-----------+-----------------+
|expires_at |float |Implemented|MUST |Unix timestamp |
| | | | |after which this |
| | | | |receipt MUST NOT |
| | | | |be accepted. |
| | | | |(Section 5.9). |
+--------------------+--------+-----------+-----------+-----------------+
|max_clock_skew |float |Implemented|SHOULD |Maximum |
| | | | |acceptable clock |
| | | | |skew in seconds. |
| | | | |Default: 30.0. |
| | | | |(Section 5.9). |
+--------------------+--------+-----------+-----------+-----------------+
|signature |string |Implemented|MUST |Ed25519 signature|
| |(128-char| | |over canonical |
| |hex) | | |JSON of all |
| | | | |receipt fields |
| | | | |(RFC 8785). |
+--------------------+--------+-----------+-----------+-----------------+
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
Wang Expires 10 February 2027 [Page 9]
Internet-Draft CCS Receipt and Binding Specification August 2026
hexadecimal characters of the full 64-character hex digest.
*Extended signing payload (Implemented, for AEC mapping):* When the
extended fields (Section 3.1) 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. The signature field (field 22) is
computed over the canonical JSON (RFC 8785) of all receipt fields.
*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 (all fields implemented):
{
"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 full receipt with all 22 fields:
{
"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",
Wang Expires 10 February 2027 [Page 10]
Internet-Draft CCS Receipt and Binding Specification August 2026
"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,
"signature": "a1b2c3d4e5f6..."
}
3.4. Verifier Policy Floor
A conforming CCS verifier enforces a non-negotiable policy floor.
When a server or tool endpoint declares a security profile that is
weaker than the verifier's minimum requirements, the verifier MUST
reject the invocation rather than downgrading to match the server's
declared profile.
This requirement addresses a documented failure mode in the MCP
ecosystem where servers self-declare their security posture, and
relying parties accept the declaration at face value. This creates a
downward pressure on effective security: a server can claim "basic
auth only" and the relying party accepts, even if the relying party's
policy requires token-based authentication. Shawn Sammartano's N-AALP
analysis identifies this as a systemic risk in protocol-level security
negotiation.
The verifier policy floor is enforced at the verification step,
before the tool invocation proceeds. The floor is determined by the
verifier's canonical configuration (Section 4) and is bound into the
receipt via the config_hash field. Any attempt to weaken the floor
results in a config_hash mismatch, detectable by downstream consumers.
*Implementation:* The verifier's canonical configuration includes a
policy_floor field that specifies the minimum acceptable security
requirements. During verification, the verifier compares the server's
declared profile against this floor. If the declared profile is
weaker, the verifier MUST return a deny verdict with block_reason set
to "policy_floor_violation".
*Rationale:* This principle aligns with the N-AALP approach of
treating unrecognized effects as destructive (fail closed). The
verifier does not trust the server's self-assessment; it applies its
own policy unconditionally.
Wang Expires 10 February 2027 [Page 11]
Internet-Draft CCS Receipt and Binding Specification August 2026
3.5. Verification Outcome States
A CCS verifier produces one of three verdict values:
* *allow*: The invocation passed all verification dimensions. The
receipt attests to a positive governance decision.
* *deny*: The invocation failed one or more verification dimensions.
The receipt attests to a blocked invocation.
* *escalate*: The verifier cannot make a definitive determination
based on available evidence. The invocation is deferred to a
higher-authority decision maker.
These three verdict values (allow, deny, escalate) constitute the
CCS evidence sufficiency axis. In the broader AEB framework, five
evidence sufficiency verdicts are defined; CCS maps to three of
them. This axis is independent from the executor lifecycle axis,
as confirmed through the agent2agent discussion with Iman Schrock
(AEB-03).
In addition to these verdict states, the verifier MAY record an
*outcome_status* field that captures the epistemic state of the
verification result regarding the action's outcome:
* *confirmed*: The outcome is fully observable. The verifier has
evidence that the action was executed and can verify the result.
* *dispatched*: The verifier authorized the invocation but has no
evidence of the outcome. The action was consumed but the result
is structurally unknowable to this verifier.
* *indeterminate*: The outcome cannot be determined because the
effecting side exposes neither readback nor compensation. This is
a terminal state when no reconciliation mechanism exists. The
verifier MUST keep the record open and MUST NOT permit blind
retries.
INDETERMINATE is not a sixth verdict. It is a state on the executor
lifecycle axis -- it describes what the verifier knows about the
outcome after the verdict was issued, not the verdict itself. This
distinction is critical: admissible evidence and indeterminate effect
can coexist. A verifier may have full confidence in the pre-
invocation evidence (the receipt is valid, the bindings are intact)
while having no visibility into what happened after execution.
The outcome_status is orthogonal to the verdict. A deny verdict is
always confirmed (the invocation was blocked locally). An allow
verdict MAY be dispatched or indeterminate if the verifier has no
Wang Expires 10 February 2027 [Page 12]
Internet-Draft CCS Receipt and Binding Specification August 2026
post-invocation visibility.
*Severity and reconcilability are independent axes.* A destructive
write with authenticated callback is high-severity but reconcilable.
A breaker trip with no telemetry is high-severity and indeterminate.
Conflating these into a single severity label produces incorrect
behavior in at least one axis. Blake Morrison's analysis of OT
command authority (draft-morrison-ot-command-authority) further
supports this separation, noting that executor lifecycle states
(B3-y classification) are independent from evidence admissibility.
*Contributors:* The distinction between evidence sufficiency and
executor lifecycle was developed through discussion with Iman Schrock
(AEB-03) and Blake Morrison (CAE 3.3/3.4, executor lifecycle, B3-y).
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:
{
Wang Expires 10 February 2027 [Page 13]
Internet-Draft CCS Receipt and Binding Specification August 2026
"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
Wang Expires 10 February 2027 [Page 14]
Internet-Draft CCS Receipt and Binding Specification August 2026
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:* Implemented in ccs-verifier 0.4.1.
The 0.4.1 implementation provides full SHA-256 request_hash binding
in addition to the params_hash coverage.
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:* Implemented in ccs-verifier 0.4.1.
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",
Wang Expires 10 February 2027 [Page 15]
Internet-Draft CCS Receipt and Binding Specification August 2026
"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:* Implemented in ccs-verifier 0.4.1.
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:* Implemented in ccs-verifier 0.4.1 (14 enum values).
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.
Wang Expires 10 February 2027 [Page 16]
Internet-Draft CCS Receipt and Binding Specification August 2026
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:* Implemented in ccs-verifier 0.4.1.
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:* Implemented in ccs-verifier 0.4.1.
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:* Implemented in ccs-verifier 0.4.1 (UUID4-based nonce).
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.
Wang Expires 10 February 2027 [Page 17]
Internet-Draft CCS Receipt and Binding Specification August 2026
* 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:* Implemented in ccs-verifier 0.4.1.
5.10. Receipt Time-Binding
A CCS receipt captures the verification moment -- not merely "was this
approved" but "when was this verified and what was the evidence at that
moment." The timestamp, verified_at, issued_at, and expires_at fields
together establish a temporal context that enables retroactive
reconciliation.
This design supports the following temporal authorization properties:
* *Verification-moment binding*: The receipt attests to the state of
knowledge at the time of verification, not at the time of
authorization grant. A pre-declared approval may be valid but
stale; the receipt records what was actually verified.
* *Post-hoc reconciliation*: When new evidence arrives (e.g., a
readback from the effecting side), the receipt can be correlated
with the new evidence using the trace_id and timestamp. This
enables reconciliation even when at-the-moment approval was not
feasible.
* *Durable record*: The receipt survives transport, retries, and
principal changes. It provides a stable reference point for
auditing the temporal chain of decisions.
For breaker-class operations where pre-declared approval may not
suffice, the receipt SHOULD encode the verification context -- what was
known, what was uncertain, and what the failure mode was if the context
was wrong. This aligns with Blake Morrison's analysis of OT command
authority, which notes that temporal binding is essential for
operations that have irreversible physical effects.
6. Key Management
Wang Expires 10 February 2027 [Page 18]
Internet-Draft CCS Receipt and Binding Specification August 2026
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 (Implemented in v0.4.1, 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
Wang Expires 10 February 2027 [Page 19]
Internet-Draft CCS Receipt and Binding Specification August 2026
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 (Implemented):* 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 |
Wang Expires 10 February 2027 [Page 20]
Internet-Draft CCS Receipt and Binding Specification August 2026
+==================+==================+=======================+
| 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 | 7.5us P50 | OOP Unix-socket |
| | (measured, | P50~133us / TCP+TLS |
| | 1000 iterations) | P50~200us (measured) |
+------------------+------------------+-----------------------+
| Implementation | Implemented + | Implemented + tested |
| status | tested (0.4.1) | (0.4.1): Unix-socket |
| | | (tests/test_unix_sock-|
| | | et_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 (1000
iterations). 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.
Wang Expires 10 February 2027 [Page 21]
Internet-Draft CCS Receipt and Binding Specification August 2026
*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 + Ed25519 Signing (Implemented in
Wang Expires 10 February 2027 [Page 22]
Internet-Draft CCS Receipt and Binding Specification August 2026
v0.4.1):*
In addition to Level 0, the verifier produces receipts with all 22
fields: request_hash, config_hash, response_hash, runtime_context_hash,
action (CAID-compatible, 14 enum values), issuer, audience, nonce
(UUID4-based), sequence, issued_at, expires_at, max_clock_skew, and
signature. Ed25519 signing is supported as the primary signature
algorithm alongside HMAC-SHA256.
A Level 1 implementation provides all 22 fields required for AEC
composition, with Ed25519 signatures providing non-repudiation.
Performance: P50=75.6us sign+verify cycle (13.2x margin below 1000us
target).
*Level 2 -- Out-of-Process Full Isolation:*
In addition to Level 1, the verifier operates out-of-process with
Unix-socket or TCP+TLS transport. The signing key is held only in the
verifier process. Cross-replica replay prevention is implemented via
shared durable state.
A Level 2 implementation provides process isolation, key protection,
and 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 -- Multi-Hop Verification:*
In addition to Level 2, the verifier supports chain-of-custody
verification across multiple executor hops. Each hop produces its own
receipt with local audience binding. The verifier policy floor
(Section 3.4) is non-negotiable from the server side.
A Level 3 implementation provides the strongest security guarantees:
process isolation, key protection, distributed replay prevention, and
multi-hop chain-of-custody verification.
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
Wang Expires 10 February 2027 [Page 23]
Internet-Draft CCS Receipt and Binding Specification August 2026
*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
Wang Expires 10 February 2027 [Page 24]
Internet-Draft CCS Receipt and Binding Specification August 2026
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:
Wang Expires 10 February 2027 [Page 25]
Internet-Draft CCS Receipt and Binding Specification August 2026
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 out-of-process transport (Unix-socket or TCP+TLS) is not available. 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.
Wang Expires 10 February 2027 [Page 26]
Internet-Draft CCS Receipt and Binding Specification August 2026
*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
Wang Expires 10 February 2027 [Page 27]
Internet-Draft CCS Receipt and Binding Specification August 2026
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).
*Verifier policy floor degradation.* A Class C verifier (self-declared)
may declare a weaker policy floor than what a relying party requires.
The verifier policy floor requirement (Section 3.4) mandates that the
verifier's floor is non-negotiable. However, if a deployment bypasses
this requirement (e.g., by patching the verifier), the effective
security drops to whatever the server declares. This is the same
failure mode documented in the MCP ecosystem by Shawn Sammartano's
N-AALP analysis. Mitigation: independent auditing (Class B) or out-
of-process deployment with independent operator (Class A).
*Outcome status confusion.* If severity and reconcilability are
conflated into a single label, implementations may incorrectly assume
that a high-severity action is always reconcilable (or vice versa).
The outcome_status field (Section 3.5) separates these axes explicitly.
Implementations MUST NOT treat outcome_status as a verdict or use it to
override the verdict decision.
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, March 1997,
<https://www.rfc-editor.org/info/rfc2119>.
[RFC7493] Bray, T., Ed., "The I-JSON Message Format", RFC 7493,
DOI 10.17487/RFC7493, March 2015,
<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,
May 2017, <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, June 2020,
Wang Expires 10 February 2027 [Page 28]
Internet-Draft CCS Receipt and Binding Specification August 2026
<https://www.rfc-editor.org/info/rfc8785>.
13.2. Informative References
[CCS-FORMAL]
Wang, G., "CCS Formal Framework",
DOI 10.5281/zenodo.21271910, 2026,
<https://doi.org/10.5281/zenodo.21271910>.
[CWE-636] MITRE, M., "CWE-636: Not Failing Securely (Fail Open)",
2026, <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, 2 August
2026, <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, 3 August 2026,
<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|
Wang Expires 10 February 2027 [Page 29]
Internet-Draft CCS Receipt and Binding Specification August 2026
| | | | | | |timestamp |
+--+--------------------+-------+-----+-----------+------+------------+
|9 |block_reason |string |0 |Implemented|No |Deny/ |
| | | | | | |escalate |
| | | | | | |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 | | | |canonical |
| | | | | | |config |
+--+--------------------+-------+-----+-----------+------+------------+
|12|response_hash |hex |1 |Implemented|Post- |SHA-256 of |
| | |string | | |hoc |response |
+--+--------------------+-------+-----+-----------+------+------------+
|13|runtime_context_hash|hex |1 |Implemented|Yes |SHA-256 of |
| | |string | | | |runtime |
| | | | | | |context |
+--+--------------------+-------+-----+-----------+------+------------+
|14|action |string |1 |Implemented|Yes |CAID- |
| | | | | | |compatible |
| | | | | | |action ID |
+--+--------------------+-------+-----+-----------+------+------------+
|15|issuer |URI |1 |Implemented|Yes |Verifier |
| | |string | | | |identifier |
+--+--------------------+-------+-----+-----------+------+------------+
|16|audience |URI |1 |Implemented|Yes |Intended |
| | |string | | | |consumer |
+--+--------------------+-------+-----+-----------+------+------------+
|17|nonce |hex |1 |Implemented|Yes |Single-use |
| | |string | | | |anti-replay |
+--+--------------------+-------+-----+-----------+------+------------+
|18|sequence |integer|1 |Implemented|Yes |Monotonic |
| | | | | | |counter |
+--+--------------------+-------+-----+-----------+------+------------+
|19|issued_at |float |1 |Implemented|Yes |Issue |
| | | | | | |timestamp |
+--+--------------------+-------+-----+-----------+------+------------+
|20|expires_at |float |1 |Implemented|Yes |Expiry |
| | | | | | |timestamp |
+--+--------------------+-------+-----+-----------+------+------------+
|21|max_clock_skew |float |1 |Implemented|Yes |Clock |
| | | | | | |tolerance |
| | | | | | |(seconds) |
+--+--------------------+-------+-----+-----------+------+------------+
|22|signature |128-char|1 |Implemented|Yes |Ed25519 |
| | |hex | | | |signature |
Wang Expires 10 February 2027 [Page 30]
Internet-Draft CCS Receipt and Binding Specification August 2026
| | | | | | |over |
| | | | | | |canonical |
| | | | | | |JSON |
+--+--------------------+-------+-----+-----------+------+------------+
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)"
}
}
Wang Expires 10 February 2027 [Page 31]
Internet-Draft CCS Receipt and Binding Specification August 2026
Author's Address
Guigui Wang
Correctover
Xiamen, Fujian
China
Email: wgg234114134@163.com
URI: https://www.correctover.com
Wang Expires 10 February 2027 [Page 32]