--- title: "Execution Context Tokens for Distributed Agentic Workflows" abbrev: "WIMSE Execution Context" category: std docname: draft-nennemann-wimse-ect-01 submissiontype: IETF number: date: v: 3 area: "ART" workgroup: "WIMSE" keyword: - execution context - workload identity - agentic workflows - audit trail - assurance levels author: - fullname: Christian Nennemann organization: Independent Researcher email: ietf@nennemann.de normative: RFC7515: RFC7517: RFC7519: RFC7518: RFC9562: RFC9110: informative: RFC8693: I-D.ietf-wimse-arch: I-D.ietf-wimse-s2s-protocol: SPIFFE: title: "Secure Production Identity Framework for Everyone (SPIFFE)" target: https://spiffe.io/docs/latest/spiffe-about/overview/ date: false OPENTELEMETRY: title: "OpenTelemetry Specification" target: https://opentelemetry.io/docs/specs/otel/ date: false author: - org: Cloud Native Computing Foundation I-D.ietf-scitt-architecture: RFC9449: I-D.ietf-oauth-transaction-tokens: I-D.oauth-transaction-tokens-for-agents: --- abstract This document defines Execution Context Tokens (ECTs), a JWT-based mechanism for recording task execution across distributed agentic workflows. Each ECT captures a single task, linked to predecessor tasks through a directed acyclic graph (DAG). ECTs are transported in a new Execution-Context HTTP header field. While designed for use with the WIMSE architecture, ECTs are identity-framework agnostic and can operate with any asymmetric key infrastructure including WIMSE WIT/WPT, X.509 certificates, OAuth-based credentials, or plain JWK sets. This revision introduces three assurance levels — Level 1 (unsigned JSON), Level 2 (JOSE asymmetric signing), and Level 3 (JOSE signing with audit ledger) — allowing deployments to choose the appropriate trade-off between simplicity and regulatory compliance. --- middle # Introduction Frameworks such as WIMSE {{I-D.ietf-wimse-arch}} authenticate workloads across call chains but do not record what those workloads actually did. This document defines Execution Context Tokens (ECTs), a JWT-based mechanism that fills the gap between workload identity and execution accountability. Each ECT captures a single task, linked to predecessor tasks through a directed acyclic graph (DAG). ECTs are designed for use with the WIMSE signing model but can operate with any identity framework that provides asymmetric key pairs with verifiable binding to agent identity. ## Scope and Applicability This document defines: - The Execution Context Token (ECT) format ({{ect-format}}) - Three assurance levels for ECT production and verification ({{level-1}}, {{level-2}}, {{level-3}}) - DAG structure for task dependency ordering ({{dag-validation}}) - An HTTP header for ECT transport ({{http-header}}) - Audit ledger interface requirements ({{ledger-interface}}) The following are out of scope and are handled by the deployment's identity framework (e.g., WIMSE, X.509 PKI, OAuth): - Workload authentication and identity provisioning - Key distribution and management - Trust domain establishment and management - Credential lifecycle management ## Assurance Levels and Applicability {#assurance-levels} ECTs support three assurance levels that govern how tokens are produced, transported, and verified. Each level builds on the payload structure defined in {{ect-payload}}. Level 1 (L1) — Unsigned JSON: : ECTs are plain JSON objects with no cryptographic signature. Integrity depends on transport security (TLS). L1 is intended for internal deployments within a single trust domain where non-repudiation is not required, such as development environments or internal microservice meshes. Level 2 (L2) — JOSE Asymmetric Signing: : ECTs are signed as JWS Compact Serialization tokens using asymmetric keys bound to the agent's identity credential. L2 provides non-repudiation and tamper detection. This is the baseline assurance level for cross-organization and peer-to-peer deployments. L2 corresponds to the behavior defined in draft-nennemann-wimse-ect-00. Level 3 (L3) — JOSE Signing with Audit Ledger: : L3 extends L2 by requiring that every ECT be recorded in an audit ledger with cryptographic commitment (hash chain, Merkle tree, or equivalent). L3 is intended for regulated environments that require hash-committed audit trails with tamper-evident history. Assurance level selection is orthogonal to human-in-the-loop (HITL) policy: any level may be combined with HITL requirements. Level selection guidance is provided in {{level-selection}}. # Conventions and Definitions {::boilerplate bcp14-tagged} The following terms are used in this document: Agent: : An autonomous workload that executes tasks within a workflow. In WIMSE deployments, this corresponds to a WIMSE workload {{I-D.ietf-wimse-arch}}. Task: : A discrete unit of agent work that consumes inputs and produces outputs. Directed Acyclic Graph (DAG): : A graph structure representing task dependency ordering where edges are directed and no cycles exist. Execution Context Token (ECT): : A token defined by this specification that records task execution details. At Level 2 and Level 3, an ECT is a signed JSON Web Token {{RFC7519}}. At Level 1, an ECT is an unsigned JSON object with the same payload structure. Identity Credential: : A credential that proves an agent's identity, such as a WIMSE Workload Identity Token (WIT), an X.509 certificate, an OAuth client credential, or a JWK with out-of-band binding. See {{identity-binding}}. Assurance Level: : One of three tiers (L1, L2, L3) governing how an ECT is produced, transported, and verified. See {{assurance-levels}}. Audit Ledger: : An append-only, immutable log of all ECTs within a workflow or set of workflows, used for audit and verification. Trust Domain: : An administrative boundary within which agents share a common identity authority. In WIMSE deployments, this corresponds to a SPIFFE {{SPIFFE}} trust domain. # Execution Context Token Format {#ect-format} An Execution Context Token records a single task in a distributed workflow. The ECT payload structure is common across all assurance levels; only the envelope and verification requirements differ. ## ECT Payload Structure {#ect-payload} The ECT payload is a JSON object containing the claims defined in this section. ### Standard Claims The following standard JWT claims {{RFC7519}} are defined for ECTs: iss: : RECOMMENDED. StringOrURI. A URI identifying the issuer of the ECT. The value MUST correspond to the agent's identity as asserted by its identity credential (see {{identity-binding}}). In WIMSE deployments, this SHOULD be the workload's SPIFFE ID in the format `spiffe:///`. Other deployments MAY use HTTPS URLs, URN:UUID identifiers, or other URI schemes appropriate to the identity framework in use. The "iss" claim is REQUIRED for L2 and L3 deployments (see {{l2-verification}} and {{l3-verification}}). aud: : RECOMMENDED. StringOrURI or array of StringOrURI. The intended recipient(s) of the ECT. The "aud" claim SHOULD contain the identifiers of all entities that will verify the ECT. When an ECT must be verified by both the next agent and the audit ledger independently, "aud" MUST be an array containing both identifiers. Each verifier checks that its own identity appears in "aud". The "aud" claim is REQUIRED for L2 and L3 deployments (see {{l2-verification}} and {{l3-verification}}). iat: : REQUIRED. NumericDate. The time at which the ECT was issued. exp: : REQUIRED. NumericDate. The expiration time of the ECT. Implementations SHOULD set this to 5 to 15 minutes after "iat". jti: : REQUIRED. String. A unique identifier for both the ECT and the task it records, in UUID format {{RFC9562}}. The "jti" serves as both the token identifier (for replay detection) and the task identifier (for DAG parent references in "par"). Receivers MUST reject ECTs whose "jti" has already been seen within the expiration window. When "wid" is present, uniqueness is scoped to the workflow; when "wid" is absent, uniqueness MUST be enforced globally across the ECT store. ### Execution Context Claims {#exec-claims} The following claims are defined by this specification: wid: : OPTIONAL. String. A workflow identifier that groups related ECTs into a single workflow. When present, MUST be a UUID {{RFC9562}}. exec_act: : REQUIRED. String. The action or task type identifier describing what the agent performed (e.g., "process_payment", "validate_safety"). This claim name avoids collision with the "act" (Actor) claim registered by {{RFC8693}}. par: : REQUIRED. Array of strings. Parent task identifiers representing DAG dependencies. Each element MUST be the "jti" value of a previously verified ECT. An empty array indicates a root task with no dependencies. A workflow MAY contain multiple root tasks. ### Data Integrity Claims {#data-integrity-claims} The following claims provide integrity verification for task inputs and outputs without revealing the data itself: inp_hash: : OPTIONAL. String. The base64url encoding (without padding) of the SHA-256 hash of the input data, computed over the raw octets of the input. SHA-256 is the mandatory algorithm with no algorithm prefix in the value, consistent with {{RFC9449}} and {{I-D.ietf-wimse-s2s-protocol}}. out_hash: : OPTIONAL. String. The base64url encoding (without padding) of the SHA-256 hash of the output data, using the same format as "inp_hash". ### Extension Claims {#extension-claims} ext: : OPTIONAL. Object. A general-purpose extension object for domain-specific claims not defined by this specification. Implementations that do not understand extension claims MUST ignore them. Extension key names SHOULD use reverse domain notation (e.g., "com.example.custom_field") to avoid collisions. The serialized "ext" object SHOULD NOT exceed 4096 bytes and SHOULD NOT exceed a nesting depth of 5 levels. ## Complete ECT Payload Example The following is a complete ECT payload example. This payload structure is the same at all assurance levels; only the transport envelope differs. ~~~json { "iss": "spiffe://example.com/agent/clinical", "aud": "spiffe://example.com/agent/safety", "iat": 1772064150, "exp": 1772064750, "jti": "550e8400-e29b-41d4-a716-446655440001", "wid": "a0b1c2d3-e4f5-6789-abcd-ef0123456789", "exec_act": "recommend_treatment", "par": [], "inp_hash": "n4bQgYhMfWWaL-qgxVrQFaO_TxsrC4Is0V1sFbDwCgg", "out_hash": "LCa0a2j_xo_5m0U8HTBBNBNCLXBkg7-g-YpeiGJm564", "ext": { "com.example.trace_id": "abc123" } } ~~~ {: #fig-full-ect title="Complete ECT Payload Example"} ## Level 1: Unsigned JSON {#level-1} At Level 1, an ECT is a plain JSON object carrying the payload defined in {{ect-payload}}. No cryptographic signature is applied. ### L1 Transport {#l1-transport} L1 ECTs are transported as serialized JSON. Two mechanisms are defined: HTTP Header: : The Execution-Context header field ({{http-header}}) carries the base64url-encoded JSON payload (without padding). HTTP Body: : When the ECT is the primary request payload, the ECT MAY be carried in the HTTP request body with Content-Type `application/json`. L1 ECTs MUST be transmitted over TLS or mTLS connections. Transport security is the sole integrity mechanism at this level. ### L1 Verification {#l1-verification} When an agent receives an L1 ECT, it MUST perform the following verification steps: 1. Parse the JSON object. 2. Verify that all required claims ("jti", "iat", "exp", "exec_act", "par") are present and well-formed. 3. Verify the "exp" claim indicates the ECT has not expired. 4. Verify the "iat" claim is not unreasonably far in the past (RECOMMENDED maximum: 15 minutes) and is not unreasonably far in the future (RECOMMENDED: no more than 30 seconds ahead of the verifier's current time). 5. Perform DAG validation per {{dag-validation}}. If any verification step fails, the ECT MUST be rejected and the failure MUST be logged. ### L1 Security Properties and Applicability {#l1-security} L1 provides the following security properties: - Structural integrity via JSON schema validation - Temporal ordering via "iat" and "exp" claims - DAG integrity via parent reference validation - Transport integrity via TLS L1 does NOT provide: - Non-repudiation (no signature binds the ECT to its issuer) - Tamper detection after delivery (the recipient cannot prove the ECT was not modified after receipt) - Issuer authentication at the ECT layer (identity depends entirely on the transport layer) L1 MUST NOT be used across trust domain boundaries. Deployments using L1 SHOULD restrict it to internal environments where all agents are operated by the same organization and transport security is considered sufficient. ## Level 2: JOSE Asymmetric Signing {#level-2} At Level 2, an ECT is a JSON Web Token (JWT) {{RFC7519}} signed as a JSON Web Signature (JWS) {{RFC7515}}. L2 corresponds to the signing behavior defined in draft-nennemann-wimse-ect-00. ECTs MUST use JWS Compact Serialization (the base64url-encoded `header.payload.signature` format) so that they can be carried in a single HTTP header value. The ECT MUST be signed with a private key that is verifiably bound to the agent's identity credential (see {{identity-binding}}). The JOSE header "kid" parameter MUST reference the public key identifier from the agent's identity credential, and the "alg" parameter MUST match the algorithm associated with that credential. ### L2 JOSE Header {#jose-header} The ECT JOSE header MUST contain the following parameters: ~~~json { "alg": "ES256", "typ": "exec+jwt", "kid": "agent-a-key-id-123" } ~~~ {: #fig-header title="ECT JOSE Header Example"} alg: : REQUIRED. The digital signature algorithm used to sign the ECT. MUST match the algorithm associated with the agent's identity credential. Implementations MUST support ES256 {{RFC7518}}. The "alg" value MUST NOT be "none". Symmetric algorithms (e.g., HS256, HS384, HS512) MUST NOT be used, as ECTs require asymmetric signatures for non-repudiation. typ: : REQUIRED. MUST be set to "exec+jwt" to distinguish ECTs from other JWT types. WIMSE deployments MAY use "wimse-exec+jwt" for backward compatibility with draft-nennemann-wimse-ect-00. Verifiers MUST accept both values. kid: : REQUIRED. The key identifier referencing the public key from the agent's identity credential {{RFC7517}}. Used by verifiers to look up the correct public key for signature verification. In WIMSE deployments, this references the WIT public key. In X.509 deployments, this MAY be the certificate thumbprint or subject key identifier. ### L2 Transport {#l2-transport} L2 ECTs are transported in the Execution-Context HTTP header field ({{http-header}}) as JWS Compact Serialization. The header field value consists of three Base64url-encoded parts separated by period (".") characters. L2 ECTs MUST be transmitted over TLS or mTLS connections. ### L2 Verification {#l2-verification} When an agent receives an L2 ECT, it MUST perform the following verification steps in order: 1. Parse the JWS Compact Serialization to extract the JOSE header, payload, and signature components per {{RFC7515}}. 2. Verify that the "typ" header parameter is "exec+jwt" or "wimse-exec+jwt". 3. Verify that the "alg" header parameter appears in the verifier's configured allowlist of accepted signing algorithms. The allowlist MUST NOT include "none" or any symmetric algorithm (e.g., HS256, HS384, HS512). Implementations MUST include ES256 in the allowlist; additional asymmetric algorithms MAY be included per deployment policy. 4. Verify the "kid" header parameter references a known, valid public key from an identity credential within the trust domain (see {{identity-binding}}). 5. Retrieve the public key identified by "kid" and verify the JWS signature per {{RFC7515}} Section 5.2. 6. Verify that the signing key identified by "kid" has not been revoked within the trust domain. Implementations MUST check the key's revocation status using the identity framework's key lifecycle mechanism (e.g., certificate revocation list, OCSP, SPIFFE trust bundle updates, or JWK set rotation). 7. Verify the "alg" header parameter matches the algorithm associated with the agent's identity credential. 8. Verify the "iss" claim is present and matches the agent identity asserted by the identity credential associated with the "kid" public key (see {{identity-binding}}). 9. Verify the "aud" claim is present and contains the verifier's own identity. When "aud" is an array, it is sufficient that the verifier's identity appears as one element; the presence of other audience values does not cause verification failure. When the verifier is the audit ledger, the ledger's own identity MUST appear in "aud". 10. Verify the "exp" claim indicates the ECT has not expired. 11. Verify the "iat" claim is not unreasonably far in the past (implementation-specific threshold, RECOMMENDED maximum of 15 minutes) and is not unreasonably far in the future (RECOMMENDED: no more than 30 seconds ahead of the verifier's current time, to account for clock skew). 12. Verify all required claims ("jti", "exec_act", "par") are present and well-formed. 13. Perform DAG validation per {{dag-validation}}. 14. If all checks pass and an audit ledger is deployed, the ECT SHOULD be appended to the ledger. If any verification step fails, the ECT MUST be rejected and the failure MUST be logged for audit purposes. Error messages SHOULD NOT reveal whether specific parent task IDs exist in the ECT store, to prevent information disclosure. ### L2 Security Properties and Applicability {#l2-security} L2 provides the following security properties: - Non-repudiation (the ECT is cryptographically bound to the issuing agent via asymmetric signature) - Tamper detection (any modification invalidates the signature) - Issuer authentication (the "kid" links to the agent's identity credential) - Audience restriction (the "aud" claim limits valid verifiers) - All L1 properties (structural, temporal, DAG, transport integrity) L2 is suitable for cross-organization deployments, peer-to-peer agent communication, and any deployment requiring cryptographic non-repudiation. L2 is the RECOMMENDED default for production deployments. ## Level 3: JOSE Signing with Audit Ledger {#level-3} Level 3 extends Level 2 by requiring that every ECT be recorded in an audit ledger that provides cryptographic commitment. L3 transport and JWS signing are identical to L2; the additional requirements apply to ledger recording and verification. ### L3 Transport {#l3-transport} L3 ECTs use the same JWS Compact Serialization transport as L2 (see {{l2-transport}}). ### L3 Audit Ledger Requirements {#l3-ledger} At Level 3, the audit ledger MUST satisfy the baseline requirements defined in {{ledger-interface}} and the following additional requirements: 1. Hash Chain: Each ledger entry MUST include a cryptographic hash of the previous entry, forming a hash chain. The hash algorithm MUST be SHA-256 or stronger. 2. Cryptographic Commitment: The ledger MUST provide a mechanism for verifiable cryptographic commitment over its entries, such as Merkle tree proofs, hash chains with signed roots, or equivalent constructions. The commitment MUST allow a verifier to confirm that a specific ECT is included in the ledger at a specific position without trusting the ledger operator. 3. Receipts: Upon successful append, the ledger MUST return a receipt to the submitting agent. The receipt MUST contain the ledger sequence number, the hash of the appended ECT entry, and the cryptographic commitment proof (e.g., Merkle inclusion proof) at the time of recording. 4. Availability: The ledger MUST be accessible for verification queries by authorized entities within the trust domain. ### L3 Recording Semantics {#l3-recording} An agent producing an L3 ECT MUST attempt to record the ECT in the audit ledger. Two recording modes are defined: Synchronous Recording: : The agent submits the ECT to the ledger and waits for a receipt before transmitting the ECT to the next agent. Synchronous recording provides the strongest guarantee: the ECT is committed to the ledger before any downstream processing occurs. Asynchronous Recording: : The agent submits the ECT to the ledger and transmits the ECT to the next agent without waiting for a receipt. The agent MUST subsequently verify that the ledger accepted the ECT and MUST retain the receipt. If the ledger rejects the ECT, the agent MUST alert the workflow coordinator or log a critical error. Deployments SHOULD use synchronous recording unless latency constraints make it impractical. The recording mode SHOULD be documented in the deployment's security policy. ### L3 Verification {#l3-verification} L3 verification consists of L2 verification ({{l2-verification}}) followed by ledger verification: 1. Perform all L2 verification steps (steps 1 through 14 of {{l2-verification}}). 2. Verify the "iss" claim is present (REQUIRED at L3). 3. Verify the "aud" claim is present (REQUIRED at L3). 4. Submit the ECT to the audit ledger for recording per {{l3-recording}}. 5. Verify that the ledger returned a valid receipt containing the sequence number, ECT hash, and cryptographic commitment proof. 6. If synchronous recording is required by deployment policy and the ledger does not return a receipt within the configured timeout, the ECT MUST be treated as unverified. If any L3-specific verification step fails, the ECT MUST be rejected even if L2 verification succeeded. ### L3 Security Properties and Applicability {#l3-security} L3 provides the following security properties beyond L2: - Tamper-evident history (the hash chain detects any modification, insertion, or deletion of ledger entries) - Cryptographic commitment (Merkle proofs or equivalent allow independent verification of ledger inclusion) - Non-repudiation of recording (the receipt proves the ECT was committed at a specific time and position) - All L2 properties L3 is intended for regulated environments requiring auditable, tamper-evident execution records, such as healthcare (FDA 21 CFR Part 11), financial services (MiFID II), and environments subject to the EU AI Act. ## Level Selection {#level-selection} Deployments SHOULD select the assurance level based on the following criteria: - Use L1 when all agents operate within a single trust domain, non-repudiation is not required, and transport security (TLS) is considered sufficient. Typical environments: development, testing, internal microservice meshes. - Use L2 when agents cross trust domain boundaries, when non-repudiation is required, or when agents communicate peer-to-peer across organizations. L2 is the RECOMMENDED default for production deployments. - Use L3 when regulatory requirements mandate tamper-evident audit trails with cryptographic commitment, or when the deployment must demonstrate compliance with frameworks such as FDA 21 CFR Part 11, MiFID II, or the EU AI Act. A deployment MAY use different assurance levels for different workflows within the same infrastructure. When agents at different levels interact, the higher level's verification requirements apply to the receiving agent. ## Backward Compatibility and Level Detection {#level-detection} A verifier determines the assurance level of a received ECT as follows: 1. If the Execution-Context header value or body content parses as valid JSON (not JWS Compact Serialization), the ECT is L1. 2. If the value parses as JWS Compact Serialization (three Base64url-encoded segments separated by periods), the ECT is L2 or L3. 3. L2 and L3 use the same JWS format. Differentiation between L2 and L3 is a matter of deployment policy: L3 deployments require ledger recording ({{l3-ledger}}), while L2 deployments treat ledger recording as optional. Implementations compliant with draft-nennemann-wimse-ect-00 are L2-compatible. No changes to existing -00 implementations are required for L2 interoperability. ## Identity Binding {#identity-binding} At L2 and L3, the ECT signing key MUST be verifiably bound to the agent's identity. This specification defines the abstract requirements for identity binding; concrete bindings are defined for specific identity frameworks. An identity binding MUST satisfy the following requirements: 1. Key Association: The "kid" value in the ECT JOSE header MUST resolve to a public key through the identity framework's key discovery mechanism. 2. Issuer Correspondence: The "iss" claim in the ECT payload MUST correspond to the agent identity asserted by the identity credential containing the "kid" public key. 3. Algorithm Consistency: The "alg" value in the ECT JOSE header MUST match the algorithm associated with the identity credential. 4. Revocation Checking: The verifier MUST be able to determine whether the signing key has been revoked using the identity framework's revocation mechanism. ### WIMSE Binding {#wimse-binding} When the deployment uses the WIMSE framework {{I-D.ietf-wimse-arch}}: - The ECT "kid" references the public key from the agent's Workload Identity Token (WIT). - The ECT "iss" SHOULD be the workload's SPIFFE ID {{SPIFFE}}, matching the "sub" claim of the WIT. - The ECT "alg" MUST match the algorithm in the WIT. - Revocation is checked via the SPIFFE trust bundle or the trust domain's key lifecycle mechanism. - ECTs are transported alongside the WIT and WPT ({{I-D.ietf-wimse-s2s-protocol}}) in HTTP requests. ### X.509 Binding {#x509-binding} When the deployment uses X.509 certificates: - The ECT "kid" MAY be the certificate thumbprint (x5t) or subject key identifier. - The ECT "iss" SHOULD be a URI derived from the certificate subject or subject alternative name. - Revocation is checked via CRL or OCSP. ### JWK Set Binding {#jwk-binding} When the deployment uses plain JWK sets {{RFC7517}} with out-of-band trust establishment: - The ECT "kid" MUST match the "kid" parameter in a JWK from the trusted JWK set. - The ECT "iss" MUST match a value associated with the JWK through the deployment's configuration. - Revocation is handled by removing the key from the published JWK set. # HTTP Header Transport {#http-header} ## Execution-Context Header Field This specification defines the Execution-Context HTTP header field {{RFC9110}} for transporting ECTs between agents. The format of the header field value depends on the assurance level: - At Level 1, the header field value is the base64url-encoded JSON payload (without padding). - At Level 2 and Level 3, the header field value is the ECT in JWS Compact Serialization format {{RFC7515}}. The value consists of three Base64url-encoded parts separated by period (".") characters. An agent sending a request to another agent includes the Execution-Context header alongside any identity headers required by the deployment's identity framework. In WIMSE deployments, agents include the Workload-Identity header and, when available, the Workload Proof Token (WPT) per {{I-D.ietf-wimse-s2s-protocol}}. ~~~ GET /api/safety-check HTTP/1.1 Host: safety-agent.example.com Authorization: Bearer Execution-Context: eyJhbGci...ECT... ~~~ {: #fig-http-example title="HTTP Request with ECT Header"} When multiple parent tasks contribute context to a single request, multiple Execution-Context header field lines MAY be included, each carrying a separate ECT. This applies to all assurance levels. When a receiver processes multiple Execution-Context headers, it MUST individually verify each ECT per the applicable verification procedure ({{l1-verification}}, {{l2-verification}}, or {{l3-verification}}). If any single ECT fails verification, the receiver MUST reject the entire request. The set of verified parent task IDs across all received ECTs represents the complete set of parent dependencies available for the receiving agent's subsequent ECT. # DAG Validation {#dag-validation} ECTs form a Directed Acyclic Graph (DAG) where each task references its parent tasks via the "par" claim. DAG validation is performed against the ECT store — either an audit ledger or the set of parent ECTs received inline. DAG validation applies regardless of assurance level. When receiving and verifying an ECT, implementations MUST perform the following DAG validation steps: 1. Task ID Uniqueness: The "jti" claim MUST be unique within the applicable scope (the workflow identified by "wid", or the entire ECT store if "wid" is absent). If an ECT with the same "jti" already exists, the ECT MUST be rejected. 2. Parent Existence: Every task identifier listed in the "par" array MUST correspond to a task that is available in the ECT store (either previously recorded in the ledger or received inline as a verified parent ECT). If any parent task is not found, the ECT MUST be rejected. 3. Temporal Ordering: The "iat" value of every parent task MUST NOT be greater than the "iat" value of the current task plus a configurable clock skew tolerance (RECOMMENDED: 30 seconds). That is, for each parent: `parent.iat < child.iat + clock_skew_tolerance`. The tolerance accounts for clock skew between agents; it does not guarantee strict causal ordering from timestamps alone. Causal ordering is primarily enforced by the DAG structure (parent existence in the ECT store), not by timestamps. If any parent task violates this constraint, the ECT MUST be rejected. 4. Acyclicity: Following the chain of parent references MUST NOT lead back to the current ECT's "jti". If a cycle is detected, the ECT MUST be rejected. 5. Trust Domain Consistency: Parent tasks SHOULD belong to the same trust domain or to a trust domain with which a federation relationship has been established. To prevent denial-of-service via extremely deep or wide DAGs, implementations SHOULD enforce a maximum ancestor traversal limit (RECOMMENDED: 10000 nodes). If the limit is reached before cycle detection completes, the ECT SHOULD be rejected. In distributed deployments, a parent ECT may not yet be available locally due to replication lag. Implementations MAY defer validation to allow parent ECTs to arrive, but MUST NOT treat the ECT as verified until all parent references are resolved. # Signature and Token Verification {#verification} ## Level Detection Before performing verification, the verifier MUST determine the assurance level of the received ECT per {{level-detection}}. If the ECT is L1 (unsigned JSON), the verifier follows the L1 verification procedure ({{l1-verification}}) and skips all signature-related steps. If the ECT is L2 or L3 (JWS), the verifier follows the L2 verification procedure ({{l2-verification}}) and, for L3 deployments, the additional ledger verification steps ({{l3-verification}}). ## L2/L3 Verification Procedure The L2 verification procedure is defined in {{l2-verification}}. For L3 deployments, the additional steps in {{l3-verification}} MUST also be performed. ## HTTP Error Handling When ECT verification fails during HTTP request processing, the receiving agent SHOULD respond with HTTP 403 (Forbidden) if the agent's identity credential is valid but the ECT is invalid, and HTTP 401 (Unauthorized) if the ECT signature verification fails. The response body SHOULD include a generic error indicator without revealing which specific verification step failed. The receiving agent MUST NOT process the requested action when ECT verification fails. # Audit Ledger Interface {#ledger-interface} ECTs MAY be recorded in an immutable audit ledger for compliance verification and post-hoc analysis. A ledger is OPTIONAL for L1 and L2 deployments but is REQUIRED for L3 deployments. This specification does not mandate a specific storage technology. Implementations MAY use append-only logs, databases with cryptographic commitment schemes, distributed ledgers, or any storage mechanism that provides the required properties. ## Baseline Ledger Requirements When an audit ledger is deployed, the implementation MUST provide: 1. Append-only semantics: Once an ECT is recorded, it MUST NOT be modified or deleted. 2. Ordering: The ledger MUST maintain a total ordering of ECT entries via a monotonically increasing sequence number. 3. Lookup by ECT ID: The ledger MUST support efficient retrieval of ECT entries by "jti" value. 4. Integrity verification: The ledger SHOULD provide a mechanism to verify that no entries have been tampered with (e.g., hash chains or Merkle trees). The ledger SHOULD be maintained by an entity independent of the workflow agents to reduce the risk of collusion. ## L3 Ledger Requirements At Level 3, the audit ledger MUST satisfy the baseline requirements above and the additional requirements defined in {{l3-ledger}}. In particular: - Each entry MUST include a cryptographic hash of the previous entry, forming a verifiable hash chain. - The ledger MUST provide cryptographic commitment proofs (Merkle tree proofs, signed hash chain roots, or equivalent). - The ledger MUST return a receipt upon successful append, containing the sequence number, entry hash, and commitment proof. ## Ledger Independence The audit ledger SHOULD be operated by an entity that is independent of the workflow agents. When the ledger operator and the workflow agents are controlled by the same organization, additional safeguards SHOULD be implemented, such as separation of duties between ledger administrators and agent operators, or independent ledger replicas maintained by third parties. ## L3 Ledger Verification Auditors verifying L3 ledger integrity SHOULD perform the following checks: 1. Verify the hash chain: for each entry, recompute the hash of the previous entry and confirm it matches the recorded value. 2. Verify the cryptographic commitment: validate Merkle inclusion proofs (or equivalent) for a sample or all entries. 3. Verify ECT signatures: for each ECT in the ledger, perform the L2 verification procedure ({{l2-verification}}) using the public keys valid at the time of recording. 4. Verify DAG consistency: confirm that all parent references in all ECTs resolve to valid entries in the ledger. # Security Considerations ## Threat Model The threat model considers: (1) a malicious agent that creates false ECT claims, (2) an agent whose private key has been compromised, (3) a ledger tamperer attempting to modify recorded entries, and (4) a time manipulator altering timestamps to affect perceived ordering. ## Level-Specific Security Properties {#level-security} ### Level 1 L1 provides no cryptographic binding between the ECT and its issuer. A compromised or malicious intermediary with access to the transport channel can modify L1 ECTs without detection after delivery. L1 does not provide non-repudiation: the issuer can deny having produced an ECT, and the receiver cannot prove otherwise. L1 MUST NOT be used across trust domain boundaries. L1 is appropriate only when all agents are operated by the same organization, the transport channel is fully trusted (e.g., service mesh with mTLS), and the deployment does not require non-repudiation or tamper evidence beyond transport security. ### Level 2 L2 inherits all security properties of the JWS-based ECT mechanism defined in this document. The existing security analysis (signature verification, replay prevention, key compromise, collusion) applies directly to L2. ### Level 3 L3 provides all L2 security properties plus tamper-evident history via the audit ledger's hash chain and cryptographic commitment. Modifications to ledger entries are detectable through hash chain verification. Deletions or insertions are detectable through Merkle proof validation. L3 does not prevent a compromised ledger operator from refusing to record entries (censorship), but the submitting agent's receipt mechanism ({{l3-ledger}}) provides evidence of submission. Deployments concerned about ledger censorship SHOULD use multiple independent ledger replicas. ## Self-Assertion Limitation {#self-assertion-limitation} ECTs are self-asserted by the executing agent. The agent claims what it did, and this claim is signed with its private key (at L2 and L3). A compromised or malicious agent could create ECTs with false claims (e.g., claiming an action was performed when it was not). ECTs do not independently verify that: - The claimed execution actually occurred as described - The input/output hashes correspond to the actual data processed - The agent faithfully performed the stated action The trustworthiness of ECT claims depends on the trustworthiness of the signing agent and the integrity of the broader deployment environment. ECTs provide a technical mechanism for execution recording; they do not by themselves satisfy any specific regulatory compliance requirement. ## Signature Verification For L2 and L3 deployments, ECTs MUST be signed with the agent's private key using JWS {{RFC7515}}. The signature algorithm MUST match the algorithm associated with the agent's identity credential (see {{identity-binding}}). Receivers MUST verify the ECT signature against the corresponding public key before processing any claims. Receivers MUST verify that the signing key has not been revoked within the trust domain (see step 6 in {{l2-verification}}). If signature verification fails or if the signing key has been revoked, the ECT MUST be rejected entirely and the failure MUST be logged. Implementations MUST use established JWS libraries and MUST NOT implement custom signature verification. ## Replay Attack Prevention ECTs include short expiration times (RECOMMENDED: 5-15 minutes) and audience restriction via "aud" to limit replay attacks. Implementations MUST maintain a cache of recently-seen "jti" values and MUST reject ECTs with duplicate "jti" values. For L2 and L3, each ECT is cryptographically bound to the issuing agent via "kid"; verifiers MUST confirm that "kid" resolves to the "iss" agent's key (step 8 in {{l2-verification}}). ## Man-in-the-Middle Protection ECTs MUST be transmitted over TLS or mTLS connections. When used with WIMSE {{I-D.ietf-wimse-s2s-protocol}} or similar service mesh protocols, transport security is already established. ## Key Compromise If an agent's private key is compromised, an attacker can forge ECTs that appear to originate from that agent. Mitigations: - Implementations SHOULD use short-lived keys and rotate them frequently. - Private keys SHOULD be stored in hardware security modules or equivalent secure key storage. - Trust domains MUST support rapid key revocation. ECTs recorded before key revocation remain valid historical records but SHOULD be flagged for audit purposes. New ECTs MUST NOT reference a parent ECT whose signing key is known to be revoked at creation time. ## Collusion and DAG Integrity {#collusion-and-false-claims} A single malicious agent cannot forge parent task references because DAG validation requires parent tasks to exist in the ECT store. However, multiple colluding agents could create a false execution history. Additionally, a malicious agent may omit actual parent dependencies from "par" to hide influences on its output; because ECTs are self-asserted ({{self-assertion-limitation}}), no mechanism can force complete dependency declaration. Mitigations include: - The ledger SHOULD be maintained by an entity independent of the workflow agents. - Multiple independent ledger replicas can be compared for consistency. - External auditors can compare the declared DAG against expected workflow patterns. Verifiers SHOULD validate that the declared "wid" of parent ECTs matches the "wid" of the child ECT, rejecting cross-workflow parent references unless explicitly permitted by deployment policy. ## Privilege Escalation via ECTs ECTs record execution history; they do not convey authorization. Verifiers MUST NOT interpret the presence of an ECT, or a particular set of parent references in "par", as an authorization grant. Authorization decisions MUST remain with the deployment's identity and authorization layer. ## Denial of Service Implementations SHOULD apply rate limiting to prevent excessive ECT submissions. For L2 and L3, DAG validation SHOULD be performed after signature verification to avoid wasting resources on unsigned or incorrectly signed tokens. L1 ECTs are cheaper to validate (no signature verification) but are correspondingly easier for an attacker to generate; L1 deployments SHOULD apply stricter rate limits to compensate. ## Timestamp Accuracy Implementations SHOULD use synchronized time sources (e.g., NTP) and SHOULD allow a configurable clock skew tolerance (RECOMMENDED: 30 seconds). Cross-organizational deployments MAY require a higher tolerance and SHOULD document the configured value. ## ECT Size Constraints Implementations SHOULD limit the "par" array to a maximum of 256 entries. See {{extension-claims}} for "ext" size limits. # Privacy Considerations ## Data Exposure in ECTs ECTs necessarily reveal: - Agent identities ("iss", "aud") for accountability purposes - Action descriptions ("exec_act") for audit trail completeness - Timestamps ("iat", "exp") for temporal ordering ECTs are designed to NOT reveal: - Actual input or output data values (replaced with cryptographic hashes via "inp_hash" and "out_hash") - Internal computation details or intermediate steps - Proprietary algorithms or intellectual property - Personally identifiable information (PII) Privacy exposure is equivalent across all assurance levels: the ECT payload contains the same claims regardless of whether the ECT is unsigned (L1), signed (L2), or signed with ledger recording (L3). L3 ledger recording increases the durability of the privacy-relevant data but does not increase its scope. ## Data Minimization {#data-minimization} Implementations SHOULD minimize the information included in ECTs. The "exec_act" claim SHOULD use structured identifiers (e.g., "process_payment") rather than natural language descriptions. Extension keys in "ext" ({{extension-claims}}) deserve particular attention: human-readable values risk exposing sensitive operational details. See {{extension-claims}} for guidance on using structured identifiers. ## Storage and Access Control ECTs stored in audit ledgers SHOULD be access-controlled so that only authorized auditors can read them. Implementations SHOULD consider encryption at rest for ledger storage. ECTs provide structural records of execution ordering; they are not intended for public disclosure. Full input and output data (corresponding to the hashes in ECTs) SHOULD be stored separately from the ledger with additional access controls, since auditors may need to verify hash correctness but general access to the data values is not needed. # IANA Considerations ## Media Type Registrations This document requests registration of the following media types in the "Media Types" registry maintained by IANA: ### application/exec+jwt Type name: : application Subtype name: : exec+jwt Required parameters: : none Optional parameters: : none Encoding considerations: : 8bit; at Level 2 and Level 3, an ECT is a JWT that is a JWS using the Compact Serialization, which is a sequence of Base64url-encoded values separated by period characters. At Level 1, this media type is not used; L1 ECTs use application/json. Security considerations: : See the Security Considerations section of this document. Interoperability considerations: : none Published specification: : This document Applications that use this media type: : Applications that implement agentic workflows requiring execution context tracing and audit trails. Additional information: : Magic number(s): none File extension(s): none Macintosh file type code(s): none Person and email address to contact for further information: : Christian Nennemann, ietf@nennemann.de Intended usage: : COMMON Restrictions on usage: : none Author: : Christian Nennemann Change controller: : IETF ### application/wimse-exec+jwt This document also registers "application/wimse-exec+jwt" as an alias for backward compatibility with draft-nennemann-wimse-ect-00. The registration details are identical to "application/exec+jwt" above except for the subtype name. WIMSE deployments MAY use either media type; new deployments SHOULD prefer "application/exec+jwt". ## HTTP Header Field Registration {#header-registration} This document requests registration of the following header field in the "Hypertext Transfer Protocol (HTTP) Field Name Registry" maintained by IANA: Field name: : Execution-Context Status: : permanent Specification document: : This document, {{http-header}} ## JWT Claims Registration {#claims-registration} This document requests registration of the following claims in the "JSON Web Token Claims" registry maintained by IANA: | Claim Name | Claim Description | Change Controller | Reference | |:---:|:---|:---:|:---:| | wid | Workflow Identifier | IETF | {{exec-claims}} | | exec_act | Action/Task Type | IETF | {{exec-claims}} | | par | Parent Task Identifiers | IETF | {{exec-claims}} | | inp_hash | Input Data Hash | IETF | {{data-integrity-claims}} | | out_hash | Output Data Hash | IETF | {{data-integrity-claims}} | | ext | Extension Object | IETF | {{extension-claims}} | {: #table-claims title="JWT Claims Registrations"} --- back # Use Cases {#use-cases} {:numbered="false"} This section describes representative use cases demonstrating how ECTs provide structured execution records at different assurance levels. Note: task identifiers in this section are abbreviated for readability. In production, all "jti" values are required to be UUIDs per {{exec-claims}}. ## Cross-Organization Financial Trading (L3) {:numbered="false"} In a cross-organization trading workflow, an investment bank's agents coordinate with an external credit rating agency. The agents operate in separate trust domains with a federation relationship. The DAG records that independent assessments from both organizations were completed before trade execution. This workflow uses Level 3 (JOSE signing with audit ledger) because regulatory requirements (e.g., MiFID II) mandate tamper-evident, auditable execution records. ~~~ Trust Domain: bank.example Agent A1 (Portfolio Risk): jti: task-001 par: [] iss: spiffe://bank.example/agent/risk exec_act: analyze_portfolio_risk Trust Domain: ratings.example (external) Agent B1 (Credit Rating): jti: task-002 par: [] iss: spiffe://ratings.example/agent/credit exec_act: assess_credit_rating Trust Domain: bank.example Agent A2 (Compliance): jti: task-003 par: [task-001, task-002] iss: spiffe://bank.example/agent/compliance exec_act: verify_trade_compliance Agent A3 (Execution): jti: task-004 par: [task-003] iss: spiffe://bank.example/agent/execution exec_act: execute_trade ~~~ {: #fig-finance title="Cross-Organization Trading Workflow (L3)"} The resulting DAG: ~~~ task-001 (analyze_portfolio_risk) task-002 (assess_credit_rating) [bank.example] [ratings.example] \ / v v task-003 (verify_trade_compliance) [bank.example] | v task-004 (execute_trade) [bank.example] ~~~ {: #fig-finance-dag title="Cross-Organization DAG"} Task 003 has two parents from different trust domains, demonstrating cross-organizational fan-in. The compliance agent verifies both parent ECTs — one signed by a local key and one by a federated key from the rating agency's trust domain. ## Internal Microservice Mesh (L1) {:numbered="false"} In an internal AI platform, multiple microservices coordinate to process requests. All agents operate within a single trust domain behind a service mesh with mTLS. Non-repudiation is not required; the ECTs are used for observability and debugging. This workflow uses Level 1 (unsigned JSON) because all agents are internal, the transport is fully trusted, and the overhead of cryptographic signing is not justified. ~~~ Trust Domain: internal.example Agent S1 (Preprocessor): jti: task-101 par: [] exec_act: preprocess_input Agent S2 (Model Inference): jti: task-102 par: [task-101] exec_act: run_inference Agent S3 (Postprocessor): jti: task-103 par: [task-102] exec_act: format_output ~~~ {: #fig-internal title="Internal Microservice Workflow (L1)"} # Related Work {:numbered="false"} ## WIMSE Workload Identity {:numbered="false"} The WIMSE architecture {{I-D.ietf-wimse-arch}} and service-to- service protocol {{I-D.ietf-wimse-s2s-protocol}} provide one identity foundation with which ECTs can operate. WIT/WPT answer "who is this agent?" and "does it have authority?" while ECTs record "what did this agent do?" Together they form an identity-plus-accountability framework for regulated agentic systems. ECTs define an explicit WIMSE identity binding (see {{wimse-binding}}) but are not limited to WIMSE deployments. ## OAuth 2.0 Token Exchange and the "act" Claim {:numbered="false"} {{RFC8693}} defines the OAuth 2.0 Token Exchange protocol and registers the "act" (Actor) claim in the JWT Claims registry. The "act" claim creates nested JSON objects representing a delegation chain: "who is acting on behalf of whom." While the nesting superficially resembles a chain, it is strictly linear (each "act" object contains at most one nested "act"), represents authorization delegation rather than task execution, and carries no task identifiers or input/output integrity data. The "act" chain cannot represent branching (fan-out) or convergence (fan-in) and therefore cannot form a DAG. ECTs intentionally use the distinct claim name "exec_act" for the action/task type to avoid collision with the "act" claim. The two concepts are orthogonal: "act" records "who authorized whom," ECTs record "what was done, in what order." ## Transaction Tokens {:numbered="false"} OAuth Transaction Tokens {{I-D.ietf-oauth-transaction-tokens}} propagate authorization context across workload call chains. The Txn-Token "req_wl" claim accumulates a comma-separated list of workloads that requested replacement tokens, which is the closest existing mechanism to call-chain recording. However, "req_wl" cannot form a DAG because: - It is linear: a comma-separated string with no branching or merging representation. When a workload fans out to multiple downstream services, each receives the same "req_wl" value and the branching is invisible. - It is incomplete: only workloads that request a replacement token from the Transaction Token Service appear in "req_wl"; workloads that forward the token unchanged are not recorded. - It carries no task-level granularity, no parent references, and no execution content. - It cannot represent convergence (fan-in): when two independent paths must both complete before a dependent task proceeds, a linear "req_wl" string cannot express that relationship. Extensions for agentic use cases ({{I-D.oauth-transaction-tokens-for-agents}}) add agent identity and constraints ("agentic_ctx") but no execution ordering or DAG structure. ECTs and Transaction Tokens are complementary: a Txn-Token propagates authorization context ("this request is authorized for scope X on behalf of user Y"), while an ECT records execution accountability ("task T was performed, depending on tasks P1 and P2"). An agent request could carry both a Txn-Token for authorization and an ECT for execution recording. In WIMSE deployments, the WPT "tth" claim defined in {{I-D.ietf-wimse-s2s-protocol}} can hash-bind a WPT to a co-present Txn-Token; a similar binding mechanism for ECTs is a potential future extension. ## Distributed Tracing (OpenTelemetry) {:numbered="false"} OpenTelemetry {{OPENTELEMETRY}} and similar distributed tracing systems provide observability for debugging and monitoring. ECTs differ in several important ways: at L2 and L3, ECTs are cryptographically signed per-task with the agent's private key; ECTs are tamper-evident through JWS signatures; ECTs enforce DAG validation rules; and ECTs are designed for regulatory audit rather than operational monitoring. OpenTelemetry data is typically controlled by the platform operator and can be modified or deleted without detection. ECTs and distributed traces are complementary: traces provide observability while ECTs provide execution records. ECTs may reference OpenTelemetry trace identifiers in the "ext" claim for correlation. ## W3C Provenance Data Model (PROV) {:numbered="false"} The W3C PROV Data Model defines an Entity-Activity-Agent ontology for representing provenance information. PROV's concepts map closely to ECT structures: PROV Activities correspond to ECT tasks, PROV Agents correspond to ECT-issuing agents, and PROV's "wasInformedBy" relation corresponds to ECT "par" references. However, PROV uses RDF/OWL ontologies designed for post-hoc documentation, while ECTs are runtime-embeddable JWT tokens with cryptographic signatures. ECT audit data could be exported to PROV format for interoperability with provenance-aware systems. ## SCITT (Supply Chain Integrity, Transparency, and Trust) {:numbered="false"} The SCITT architecture {{I-D.ietf-scitt-architecture}} defines a framework for transparent and auditable supply chain records. ECTs and SCITT are complementary: the ECT "wid" claim can serve as a correlation identifier in SCITT Signed Statements, linking an ECT audit trail to a supply chain transparency record. # Acknowledgments {:numbered="false"} The author thanks the WIMSE working group for their foundational work on workload identity in multi-system environments. The WIMSE concepts of Workload Identity Tokens and Workload Proof Tokens provided the original motivation for execution context tracing and remain a primary identity binding for ECTs.