| Internet-Draft | OAuth Mission Containment | August 2026 |
| McGuinness | Expires 22 February 2027 | [Page] |
Mission-Bound Authorization for OAuth 2.0 commits a Mission's
authority at a single approval event: the approved Authority Set and
its integrity anchors never change. This document defines Mission
Containment, an optional layered extension for narrowing a live
Mission without ending it. When a declared protected event fires (a
tainted read, an anomaly signal, a routed-to-approval open-world
discovery encounter), the Mission Issuer commits a contain
transition: an issuer-held, versioned overlay removes capability from
the Mission's effective authority while the Mission stays active
and the approved anchors stay immutable. Containment is monotonic and
removal-only. Token derivation, child delegation, cross-domain
projection, and offline attenuation are gated on the effective
authority; a derivation that asks only for contained capability fails
with authority_contained. Removed authority returns only through a
new approval, as a successor Mission under the expansion profile,
with the predecessor's containment history disclosed to the Approver.
A deployment that never contains a Mission is unaffected by this
document.¶
This note is to be removed before publishing as an RFC.¶
The latest revision of this draft can be found at https://mcguinness.github.io/mission-bound-authorization/draft-mcguinness-oauth-mission-containment.html. Status information for this document may be found at https://datatracker.ietf.org/doc/draft-mcguinness-oauth-mission-containment/.¶
Source for this draft and an issue tracker can be found at https://github.com/mcguinness/mission-bound-authorization.¶
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 22 February 2027.¶
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.¶
Mission-Bound Authorization for OAuth 2.0 [I-D.draft-mcguinness-oauth-mission] (the "issuance profile") makes a Mission a first-class OAuth artifact: a structured, human-approved, integrity-bound task whose authority bounds and outlives every token an agent derives. It commits the Authority Set once, at the approval event, and gates every derivation on Mission state.¶
Incident response against a live Mission has, under the profiles so far, two grains: revoke the Mission and end one body of work across every resource, or suspend it and pause all of it. A mid-task signal is often finer than either. A session reads tainted content and the right response is to remove the Mission's egress capability, not its read capability; an anomaly fires against a payment action and the right response is to remove that action, not the reconciliation work around it. This document defines that finer control: capability kill within one Mission, with the Mission still running.¶
The mechanism is a narrowing overlay, not a change to the Mission.
The approved Authority Set and its intent_hash and authority_hash
anchors are immutable; whether capability is contained is evaluated
state, not part of authority_hash, and folding it into the anchor
would make the committed authority time-varying. This is the same
argument by which the Status profile keeps an entry's fired
completion status out of the anchor
([I-D.draft-mcguinness-oauth-mission-status]). The overlay is held
by the Mission Issuer, versions independently, and only ever grows.¶
This document is optional and experimental: adopt it for evaluation,
not as a stable interface. It is a layered extension to the issuance
profile, not a change to it. A deployment that implements
[I-D.draft-mcguinness-oauth-mission] and never contains a Mission
is fully conformant to that profile and is unaffected by this
document: it holds no containment overlay, commits no contain
transition, and never emits the authority_contained denial reason.
No lifecycle state is added; a contained Mission is an active (or
suspended) Mission with a non-empty overlay.¶
A Mission Issuer claims conformance to this document only when it contains a Mission; otherwise it remains a plain issuance-profile Mission Issuer. Nothing here places a new requirement back on the issuance profile.¶
This document depends normatively on the issuance profile and is not
implementable alone. It reuses, without restating, that profile's
Mission, Mission Intent, Authority Set and entry shape, integrity
anchors, mission claim, subset rule, and lifecycle gating, and the
Status profile's state version
([I-D.draft-mcguinness-oauth-mission-status]). It uses the terms
Agent (Client), Subject, Approver, Mission Issuer, Authority Set,
Mission, and derived token as defined in the issuance profile.¶
Where this document refers to "the issuance profile" without a section, it means [I-D.draft-mcguinness-oauth-mission] as a whole.¶
This document defines:¶
the containment overlay: containment_version and the contained
set (Section 7);¶
the contain transition and its monotonicity, idempotency, and state-legality rules (Section 8);¶
protected events and the fail-closed rule for indeterminate reports (Section 9);¶
derivation gating on the Effective Authority Set (Section 10);¶
the Baseline and Runtime-Enforced containment properties (Section 12);¶
the authority_contained denial reason (Section 13);¶
visibility of containment on status and introspection surfaces (Section 14);¶
propagation over the existing state machinery (Section 15);¶
restoration, only through an approved successor Mission (Section 16);¶
the containment policy and its consent seam (Section 17); and¶
the Containment Evidence object (Section 18).¶
This document does NOT define:¶
constraint tightening within an entry (for example, lowering a
max_amount ceiling); the overlay is removal-only (Section 7.1);¶
any transition that reverts containment in place; restoration is a successor Mission (Section 16);¶
a dedicated containment event type for Signals consumers; the metadata-only lifecycle event carries the change in the interim (Section 15);¶
the content of the controls.containment Mission Intent member; it
is named as an extension point only (Section 17); or¶
how a deployment detects a tainted read or an anomaly; detection belongs to the harness, runtime, and discovery layers (Section 9).¶
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.¶
This document uses the terms Mission, Mission Intent, Authority Set, Mission Issuer, Mission-bound token, and delegation from [I-D.draft-mcguinness-oauth-mission], and state version and Effective Authority Set from [I-D.draft-mcguinness-oauth-mission-status].¶
The issuer-held, versioned record of capability removed from a Mission's effective authority (Section 7).¶
A {resource, actions} pair in the overlay's contained set. An
entry with no actions member contains the whole Authority Set
entry for that resource. It is this profile's own contribution to
the Effective Authority Set's reduction: every derivation gated
after a contain transition excludes it; authority that left the
Mission before the transition keeps its own bound, not this one
(Section 10).¶
An event class the containment policy declares as a containment trigger, whose verified occurrence commits a contain transition (Section 9).¶
The committed, metadata-only change that adds capability to the
contained set and increments containment_version
(Section 8).¶
The issuance profile uses "containment" for set containment in its subset rule; this document uses Containment for the incident-response control. Context distinguishes them.¶
This document's Containment is also distinct from trifecta containment, the runtime enforcement layer's claim that private-data exposure, untrusted-content taint, and external-communication paths are jointly gated for a Mission's governed work ([I-D.draft-mcguinness-mission-runtime], Section "Trifecta Containment"). Mission Containment narrows what a Mission's authority permits; trifecta containment is a property of how a deployment executes a Mission's work. The two compose but neither implies the other: a Mission can be contained under this document without trifecta containment holding, and trifecta containment can hold for a Mission that this document has never contained.¶
This profile is defined against the Mission model rather than against OAuth 2.0 mechanics: it is a substrate-neutral consumer, and this section is its consumption declaration under the rule of Mission Substrate Requirements ([I-D.draft-mcguinness-mission-substrate]) that a substrate-neutral profile declare the kernel functions and optional capabilities it consumes.¶
From the contextual-governance kernel it consumes the Mission
identifier and issuer, the kernel's Mission Reference and Controller,
which key the overlay and its evidence; the lifecycle state space,
the kernel's governance gate, whose states bound a contain
transition's legality (Section 8); the immutable
Approved Context, whose boundary the overlay respects: contained
capability is evaluated state, never a change to the approved value
(Section 7); and the ordered governance record, into which each
contain transition commits as a state-version increment. The kernel
requires no particular integrity anchors: intent_hash and
authority_hash are the OAuth binding's commitment to the Approved
Context, and the overlay stays outside that commitment (Section 7).¶
It consumes these optional capabilities:¶
| Capability | Consumption | Scope of consumption |
|---|---|---|
| Structured Authority | required | The Effective Authority Set is what every derivation, delegation, projection, and attenuation root is gated on after a contain transition (Section 10); a contained capability names an approved Authority Set entry or its actions (Section 7) |
| Monotonic Derivation | required | Scoped to removal-only narrowing: a contain transition only adds contained capability, so monotonicity is trivially decidable, set union over entries, with no per-constraint comparator (Section 7.1, Section 8) |
| Lifecycle-Gated Authorization | required | The Baseline property is what a lifecycle-gated substrate provides: no derivation, delegation, projection, or attenuation root minted after the transition carries contained capability (Section 12) |
| State-Observable | conditional | Consumed only for the Runtime-Enforced property: a consumer that checks a fresh, authenticated state source at or near action time denies contained capability whether or not its credential predates the transition; a consumer that never consults such a source gets Baseline only (Section 12) |
| Credential-Bound | conditional | Consumed where derivation issues Mission-bound tokens; a token issued before the transition is the same residual that revocation carries, bounded by its own exp and the deployment's freshness rules (Section 10) |
| Independently Verifiable | not consumed | This document defines no offline verification artifact or trust-anchor discovery; its evidence objects are the Mission Issuer's own audit material (Section 18) |
| Portable Evidence | not consumed | This document produces audit material of its own, the Containment Evidence object and the Protected Event Receipt, whose canonical bytes and type identifiers an audit or transparency profile registers (Section 18.2, Section 19) |
The issuance profile [I-D.draft-mcguinness-oauth-mission] is this version's base profile (this document is an OAuth-lane companion of that binding): it defines each consumed kernel function and capability for OAuth 2.0, and every OAuth artifact named in this document enters through it. A binding that provides the required capabilities above, and maps this document's representations onto its own, the Authority Set entries the overlay names and the approved-context commitment the overlay stays outside, hosts this profile's Baseline property; the Runtime-Enforced property additionally requires State-Observable (Section 12). The portability claim is capability-scoped rather than substrate-wide for the reason the substrate's Capability Confusion consideration states: every property this profile requires matches an explicit capability claim and its scope, never the generic statement that a binding supports Missions.¶
A Mission participating in this profile carries a containment overlay on its Mission record:¶
containment_version:REQUIRED. An integer, 0 at the approval event, incremented by each
contain transition, strictly monotonic per Mission. A Mission with
containment_version 0 is uncontained.¶
contained:REQUIRED when containment_version is greater than 0. An array of
contained-capability entries. Each entry is a JSON object
[RFC8259] with resource (REQUIRED, the resource of an
approved Authority Set entry) and actions (OPTIONAL, an array of
that entry's action values). An entry with no actions member
contains the whole Authority Set entry.¶
The overlay is held by the Mission Issuer. It is not part of the
Mission Intent and not part of the Authority Set, and it never enters
intent_hash or authority_hash: the approved Authority Set and its
anchors are immutable. Whether capability is contained is evaluated
state, not part of authority_hash; folding containment into the
anchor would make the committed authority time-varying, exactly as
folding an entry's fired completion status into it would
([I-D.draft-mcguinness-oauth-mission-status]).¶
The overlay removes capability; it expresses nothing else. Constraint
tightening within an entry (for example, lowering a max_amount
ceiling) is a named deferral: removal keeps monotonicity trivially
decidable, set union over entries, where tightening would need a
per-constraint comparator to prove each successive overlay no broader
than the last. A deployment that needs a tighter constraint contains
the affected actions and re-approves them, tightened, through a
successor Mission (Section 16).¶
Containment composes with the Status profile's entry discharge and
duplicates none of it. Discharge retires an entry because the task
the entry was granted for is done, under a terminal_when condition
the Approver committed inside the Authority Set; containment removes
capability because a protected event fired, under issuer-held policy
the anchor never carried. Both are evaluated state; both commit as
metadata-only state-version increments; derivation excludes both
(Section 10). Discharge identifies the retired entry by the
issuance profile's Authority Set entry commitment
([I-D.draft-mcguinness-oauth-mission]).¶
A contain transition commits additions to the contained set and
increments containment_version. Its rules:¶
Monotonic. A contain transition MUST only add contained capability: the new contained set MUST be a superset of the prior one, and a transition MUST NOT remove an entry, restore an action, or otherwise revert containment. No operation of this profile shrinks the overlay (Section 16).¶
Idempotent per event. Each contain transition is attributed to
a protected event by its event_id. A duplicate report of the same
event_id MUST NOT commit a second transition; the Mission Issuer
answers it with the already-committed result.¶
Legal states. A contain transition is legal from active and
from suspended, and MUST be refused in every terminal state. A
resume does not clear the overlay: a Mission suspended, contained,
and resumed returns to active still contained.¶
No state change. The transition changes no lifecycle state: a
contained active Mission remains active. Containment narrows
what the Mission can do, never whether it runs.¶
Each contain transition is a committed metadata-only change for the purposes of the state version, which the Status profile defines as "incremented on each committed lifecycle transition (the approval event is version 1) and each committed metadata-only change" ([I-D.draft-mcguinness-oauth-mission-status]): the Mission's state version increments at the commit, so a materialized policy view that commits a state version ([I-D.draft-mcguinness-mission-runtime]) is detectably obsolete after a containment.¶
The containment policy (Section 17) declares the event
classes that trigger containment. Representative classes, defined by
their own layers, not here: a tainted read under the harness taint
policy ([I-D.draft-mcguinness-mission-harness]), an anomaly signal
from the deployment's monitoring, and a routed_to_approval outcome
or a tainted Discovery Evidence record from open-world discovery
([I-D.draft-mcguinness-mission-discovery], Section "Discovery
Evidence"). Event-to-policy mapping stays deployment-defined: neither
the outcome nor the evidence field is, by itself, this document's
protected event.¶
A protected event is a trusted input to authority: the Mission Issuer MUST authenticate and integrity-verify an event source outside its own trust domain before acting on its report. The mechanism is deployment-defined; this document defines no interoperable event-source profile of its own.¶
A protected event whose authenticity or applicability is indeterminate fails closed. The Mission Issuer MUST either commit the narrowing the policy maps to the event or withhold derivation of the implicated capability until the report is resolved; it MUST NOT ignore the event. An unverifiable report can cost the Mission authority early; it can never preserve authority the policy would have removed.¶
The Mission Issuer MUST record a Protected Event Receipt for every protected event it receives, whether the event is applied as a contain transition or rejected (Section 19). Fail-closed means the event is rejected rather than acted on; it never means the event goes unrecorded.¶
A credential derived or delegated after a contain transition MUST NOT carry contained capability. Token derivation under a contained Mission MUST evaluate the request against the Effective Authority Set, with the issuance profile's subset rule unchanged:¶
a derivation request whose authority lies entirely within the
contained set MUST fail, with the authority_contained denial
reason (Section 13);¶
a derivation request covering both contained and uncontained capability MUST omit the contained capability: the issued token carries only the uncontained remainder; and¶
tokens already issued before the transition are the same residual
that revocation carries, bounded the same way by their own exp
and the deployment's freshness rules (Section 15).¶
The same bound applies wherever authority leaves the Mission, for every derivation gated after the transition. A Child Mission attenuates from the parent's Effective Authority Set, so a contained capability is absent from every child derivation gated after the transition; a contain transition also propagates entry-wise to every Child Mission already justified by the contained entry, so an existing child does not keep deriving it either ([I-D.draft-mcguinness-oauth-mission-child-delegation], Section "Child Mission State"). A cross-domain projection issued after the transition projects the Effective Authority Set, so a contained capability is absent from it ([I-D.draft-mcguinness-oauth-mission-cross-domain]). An offline attenuation root issued after the transition is derived from the Effective Authority Set, so no offline chain minted from it can narrow its way back to contained capability ([I-D.draft-mcguinness-oauth-mission-attenuation]).¶
What derivation gating and propagation do not reach is authority already materialized, before the transition, into a standing minting capability outside the issuer's control: a cross-domain projection grant already redeemed at a Resource AS, or an offline attenuation root already minted into a holder's possession. That residual is bounded on its own terms, not by this document (Section 11).¶
Derivation gating stops the Mission Issuer from minting new contained authority, and propagation (Section 15) carries a contain transition to every existing Child Mission it justified. Neither reaches authority the Mission already turned, before the transition, into a standing minting capability the issuer does not hold:¶
a cross-domain projection grant a Resource AS already redeemed ([I-D.draft-mcguinness-oauth-mission-cross-domain]) keeps minting local tokens from that grant for the grant's own lifetime, because the Resource AS re-derives nothing from the Mission and holds no overlay to consult; and¶
an offline attenuation root already minted into a holder's
possession ([I-D.draft-mcguinness-oauth-mission-attenuation])
keeps minting narrower offline children for its own del_max_depth
and lifetime, because the attenuation substrate defines no channel
back to the issuer for either artifact to learn of the transition.¶
This residual is the same shape as the residual an already-issued access token carries under revocation ([I-D.draft-mcguinness-oauth-mission], Section "Revocation"): authority materialized before a narrowing event outlives the event, bounded by the artifact's own lifetime rather than by a check this document adds. Containment does not widen what either artifact can do; it only fails to reach it early.¶
Closing this gap is a lifetime problem, not a protocol gap this document can add a check for: a deployment that relies on containment to bound cross-domain projection or offline attenuation SHOULD keep grant and root lifetimes short and lease or re-mint on a cadence shorter than its containment response target, so the next lease or the next root falls after the contain transition and picks up the narrowed Effective Authority Set.¶
Section 10 and Section 11 together state one containment property; a second exists only where the substrate supports it. What a consumer actually gets depends on which one it relies on:¶
a new-derivation kill. From the transition forward, no derivation,
delegation, projection, or attenuation root minted after it carries
contained capability (Section 10). A token issued before
the transition, or capability already materialized outside the
issuer's reach, can still carry the removed capability until that
artifact's own lifetime runs out (Section 11).
Baseline needs nothing of a consumer beyond the ordinary bearer
check, signature and exp: it is the property a lifecycle-gated
substrate provides ([I-D.draft-mcguinness-mission-substrate]).¶
an action-time kill. A consumer that checks a fresh, authenticated state source at or near the time of the action, Mission Status, introspection, or the runtime layer's PDP, denies contained capability whether or not the credential it evaluates predates the transition, bounded by that source's staleness plus the permit and execution windows ([I-D.draft-mcguinness-mission-runtime]). Runtime-Enforced requires the substrate to be state-observable ([I-D.draft-mcguinness-mission-substrate]); a consumer that never consults such a source gets Baseline only, however long the Mission has been contained.¶
Neither property is a deployment failure: a consumer that only checks
exp is a fully conformant Baseline consumer, and its exposure to
contained capability is bounded by token lifetime, not by a defect in
this document.¶
authority_contained:The requested capability was approved for this Mission and is currently contained.¶
The distinction from the runtime enforcement layer's
out_of_authority, the action not within the Authority Set
([I-D.draft-mcguinness-mission-authzen]), is approval history:
out_of_authority reports capability that was never approved, and
authority_contained reports capability the Approver granted and the
issuer then contained. That history is what makes the denial
expansion-eligible: once-approved authority is a candidate for
re-adjudication (Section 16), where never-approved authority is
an ordinary out-of-authority denial.¶
At the token endpoint the denial uses the issuance profile's error
vocabulary for a request outside the derivable authority and MAY
additionally carry authority_contained in the shared
mission_denial_reason member the expansion profile registers
([I-D.draft-mcguinness-oauth-mission-expansion]); this document
requests that value's registration in the Mission Denial Reasons
registry that member carries (Section 23).
A runtime enforcement deployment separately carries it as a
denial-reason identifier alongside the classification set of
[I-D.draft-mcguinness-mission-authzen], a distinct
specification-defined value space the registry does not cover: the
shared spelling is a coincidence, not a shared registration. A
consumer MUST treat an unrecognized reason code as a denial with no
further semantics.¶
Consistent with the expansion profile, the classification of a denial
as expansion-eligible belongs to the component that denies the
action; this document classifies authority_contained as
expansion-eligible, and eligibility is not an authorization in favor
of expansion.¶
A contained Mission MUST NOT present contained capability as live. When this profile runs:¶
the mission object of the Mission Status Response and the token
introspection Mission projection MUST carry containment_version
([I-D.draft-mcguinness-oauth-mission-status]);¶
any surface of those profiles that discloses Mission authority MUST omit contained capability or annotate it as contained; and¶
a mission.lifecycle-change event MUST carry containment_version,
and MAY carry authority_hash
([I-D.draft-mcguinness-oauth-mission-signals], Section 15).¶
A consumer that does not understand containment_version ignores it;
the state version already makes the change observable
(Section 8). A consumer that reads it holds a precise
question: whether the authority view it materialized predates the
current overlay.¶
Containment rides the existing state-propagation machinery and adds none:¶
Pull. The contain transition's state-version increment moves
the Mission Status Response: the next read reports the new
version and containment_version, and a materialized view naming
an older version is detectably obsolete (Section 8).¶
Status List. A contained active Mission stays active, so
its Status List bit is unchanged: the list carries reliance bits
only, and containment detail, like the state version, stays on the
authoritative surfaces
([I-D.draft-mcguinness-oauth-mission-status]). Containment binds
derivation at the issuer, so a list-only consumer's staleness never
widens what a contained Mission can issue.¶
Push. Where Signals runs, the commit is emitted as a
mission.lifecycle-change whose state equals its prior_state,
that profile's metadata-only shape, incrementing version like any
other committed change, and carrying the Mission's current
containment_version and, optionally, its authority_hash as a
reference to the Authority Set the overlay narrows
([I-D.draft-mcguinness-oauth-mission-signals]). This makes an
active-to-active version bump legible to a containment-aware
consumer as an authorization change, rather than an opaque version
increment. A dedicated containment event type is deferred; carrying
containment_version on the existing event is what keeps that
change legible in the interim.¶
How quickly a consumer must adopt the narrowed view is bounded by the freshness and staleness rules it already operates under ([I-D.draft-mcguinness-oauth-mission-status], [I-D.draft-mcguinness-mission-runtime]); this document does not restate them. The runtime profile's state-freshness rules separately recommend a containment-aware source for the remainder of a Mission carrying a nonzero overlay ([I-D.draft-mcguinness-mission-runtime], Section "Mission State and Freshness").¶
Contained authority returns only as a new approval. No transition of
this profile removes capability from the overlay; the path back is a
successor Mission adjudicated under the expansion profile
([I-D.draft-mcguinness-oauth-mission-expansion]), whose authority
comes only from its own approval event. An authority_contained
denial is the expansion-eligible signal for that path
(Section 13).¶
Two rules close the laundering gap between containment and expansion:¶
Containment MUST NOT propagate to a successor: the successor's
overlay starts empty, containment_version 0, because its
authority is whatever its own approval yields, not the
predecessor's minus a memory.¶
An expansion whose predecessor has a non-empty containment overlay MUST surface the predecessor's containment history in the expansion consent disclosure: at minimum the contained capability and the event class that contained each entry.¶
Together they keep the successor clean without letting it launder: capability removed for cause can return, but only past an Approver who saw the cause.¶
That guarantee is only as strong as the disclosure's own integrity reaching the Approver unaltered, and the issuance profile does not itself anchor consent-disclosure integrity. Where an implementation needs the containment history surfaced at expansion consent to be non-repudiable, it SHOULD commit that disclosure under the Consent Evidence companion's consent-disclosure commitment ([I-D.draft-mcguinness-oauth-mission-consent-evidence]) rather than rely on an unattested record of what the Approver was shown.¶
The map from protected event class to narrowing is the containment policy. It is issuer-held, parallel to the derivation policy by which the issuance profile derives the Authority Set: an input the issuer applies at a committed change, never content of the anchor. The client does not supply it, the Mission Intent does not carry it, and an intent-shaping component does not write it: a compromised agent, client, or shaping component MUST NOT be able to select which events contain or how far a containment narrows.¶
A deployment may want the Approver to consent to tightened
containment behavior at approval time. controls.containment, a
member of the Mission Intent's controls object under the issuance
profile's extensibility rules, is named here as that extension point;
its content is explicitly not defined by this document. An
Approver-consented member can only tighten what the issuer-held
policy would do, never loosen it.¶
The Mission Issuer MUST record a Containment Evidence object for each contain transition. This evidence is audit material and does not grant authority.¶
A Containment Evidence object is a JSON object [RFC8259] with:¶
evidence_id:REQUIRED. Unique identifier.¶
mission:REQUIRED. Mission reference: id, issuer, and authority_hash.¶
event:REQUIRED. The protected event: type, source, observed_at (an
RFC 3339 [RFC3339] date-time), and event_id.¶
policy:REQUIRED. Identifier of the containment policy rule applied.¶
prior_version, new_version:REQUIRED. The Mission's state version before and after the transition.¶
prior_containment_version, new_containment_version:REQUIRED. The overlay's version before and after the transition.¶
removed:REQUIRED. The contained-capability entries this transition added (Section 7).¶
created_at:Example:¶
{
"evidence_id": "cnt_4Tq9mV2xLp",
"mission": {
"id": "msn_8RfX2Lqv9TqMv4z7sA2bN1k0YpEdHc9-",
"issuer": "https://as.example.com",
"authority_hash":
"sha-256:tY2nD9bM7sX1cF8gH2vJ4kE5pNQl3KvZ4mP5x0wQrR6"
},
"event": {
"type": "session-taint",
"source": "https://harness.example.com",
"observed_at": "2026-11-02T09:41:00Z",
"event_id": "evt_7pQ4mK1c"
},
"policy": "contain-egress-on-taint-v3",
"prior_version": 4,
"new_version": 5,
"prior_containment_version": 0,
"new_containment_version": 1,
"removed": [
{ "resource": "https://mail.example.com",
"actions": ["messages.send"] }
],
"created_at": "2026-11-02T09:41:02Z"
}
¶
A Containment Evidence object's canonical bytes are its JCS
[RFC8785] canonicalization, and its type identifier is
application/mission-containment-evidence+json, registered by this
document (Section 23).¶
Containment Evidence records the transition a protected event drove; it has no object for a protected event the Mission Issuer rejected. The Mission Issuer MUST also record a Protected Event Receipt for the ingestion decision on every protected event it receives (Section 9), whatever the outcome, so a rejected report is recorded rather than only silently withheld.¶
A Protected Event Receipt is a JSON object [RFC8259] with:¶
receipt_id:REQUIRED. Unique identifier.¶
mission:REQUIRED. Mission reference: id, issuer, and authority_hash.¶
event:REQUIRED. The protected event, in the form Containment Evidence
carries it: type, source, observed_at (an RFC 3339 [RFC3339]
date-time), and event_id.¶
outcome:REQUIRED. One of applied or rejected.¶
policy:CONDITIONAL. Identifier of the containment policy rule applied.
REQUIRED when outcome is applied; matches the policy member of
the Containment Evidence object the transition committed
(Section 18.1).¶
rejection_reason:CONDITIONAL. A string. REQUIRED when outcome is rejected: the
reason the event was not applied (for example, an unverifiable
signature, a source not trusted for the reported event type, or a
Mission the event does not name or that is in a terminal state). A
deployment MAY define additional values, which MUST be
collision-resistant names, following the Collision-Resistant Name
guidance of [RFC7519] Section 4.2.¶
emitter:REQUIRED. An object, in the form Decision Evidence defines
([I-D.draft-mcguinness-mission-runtime-evidence]), with role
issuer.¶
created_at:REQUIRED. RFC 3339 [RFC3339] timestamp of the ingestion decision.¶
Example, a rejected report:¶
{
"receipt_id": "per_9wLq3XtN7m",
"mission": {
"id": "msn_8RfX2Lqv9TqMv4z7sA2bN1k0YpEdHc9-",
"issuer": "https://as.example.com",
"authority_hash":
"sha-256:tY2nD9bM7sX1cF8gH2vJ4kE5pNQl3KvZ4mP5x0wQrR6"
},
"event": {
"type": "session-taint",
"source": "https://harness.example.com",
"observed_at": "2026-11-02T09:40:55Z",
"event_id": "evt_2mK7pQ4c1x"
},
"outcome": "rejected",
"rejection_reason": "source_not_trusted_for_type",
"emitter": { "id": "as.example.com", "role": "issuer" },
"created_at": "2026-11-02T09:40:56Z"
}
¶
A Protected Event Receipt's canonical bytes are its JCS [RFC8785]
canonicalization, and its type identifier is
application/mission-protected-event-receipt+json, registered by this
document (Section 23), mirroring the Child and Discovery Evidence
registration conventions ([I-D.draft-mcguinness-mission-audit]).¶
An applied receipt's event_id correlates it to the Containment
Evidence object the same event produced (Section 18.1); a
rejected receipt has no corresponding Containment Evidence, because
no transition committed.¶
An implementation claims conformance to this document only in the Mission Issuer role and only when it contains a Mission. A conforming containment-capable Mission Issuer MUST:¶
hold the containment overlay per Mission and commit contain transitions under the monotonicity, idempotency, and state-legality rules of Section 8;¶
verify protected events and fail closed on an indeterminate report (Section 9);¶
gate every derivation, delegation, projection, and attenuation root
on the Effective Authority Set, and deny an all-contained request
with authority_contained (Section 10,
Section 13);¶
where it also implements Child Delegation, propagate a contain transition entry-wise to every existing Child Mission the contained entry justified ([I-D.draft-mcguinness-oauth-mission-child-delegation], Section "Child Mission State");¶
carry containment_version on its status and introspection
surfaces and never present contained capability as live
(Section 14);¶
record a Containment Evidence object per contain transition (Section 18);¶
record a Protected Event Receipt for the ingestion decision on every protected event received, applied or rejected (Section 19); and¶
where it also adjudicates expansion, start the successor uncontained and surface the predecessor's containment history at the expansion consent (Section 16).¶
A containment-capable Mission Issuer is also a conforming issuance-profile Mission Issuer ([I-D.draft-mcguinness-oauth-mission]). Containment gives every Resource Server the Baseline property with no change to the Resource Server; the Runtime-Enforced property additionally requires it to consult a fresh state source (Section 12). "No new behavior" holds only for a Resource Server that relies on Baseline: a token issued after the contain transition never carries contained capability, and a token issued before the transition can still carry it until that token's own expiry (Section 12).¶
Containment's guarantee is directional: every rule in this document moves authority in one direction, down. The risks specific to it are who can force that movement and what the movement discloses.¶
Containment is monotonic by construction: it only removes capability, so it is not a path to escalation, and a compromised or injected agent cannot use a protected event to widen authority. The worst a forged or forced event achieves is a forced premature containment, a denial-of-service on the task: authority the task still needs is withdrawn. This is the same residual the Status profile carries for forced premature discharge, bounded the same way: the event-source authentication, integrity, and fail-closed rules of Section 9 bound who can force it, and restoration remains available through a fresh approval (Section 16).¶
Whatever surface applies contain transitions, the issuer's event intake or an operator plane, holds a denial capability over live work. It is operator trust: a deployment MUST authenticate and authorize callers of that surface as it does lifecycle mutation, and SHOULD govern bulk containment with the same dry-run-first posture as bulk lifecycle operations ([I-D.draft-mcguinness-oauth-mission-management]).¶
A compromised event source can fire protected events at will. Monotonicity bounds its blast radius: every transition it forces yields too little authority, never too much. The overlay it inflates cannot be spent, delegated, or projected in any derivation gated after the transition, and propagation carries it to every Child Mission the contained entry already justified ([I-D.draft-mcguinness-oauth-mission-child-delegation], Section "Child Mission State"). The exception is the same one any adversary faces: the materialized-capability residual (Section 11), bounded by the affected artifact's own lifetime regardless of which event forced the transition. Recovery is bounded too: the poisoned Missions are enumerable from their Containment Evidence, and each restores only through an approval that sees the containment history (Section 16).¶
The disclosure rule of Section 16 is load-bearing: without it, expansion is a laundering path in which capability removed for cause returns through a successor the Approver believes is clean. An implementation that omits the predecessor's containment history from the expansion consent defeats containment for any adversary patient enough to ask again.¶
A containment overlay discloses incident posture: that an event
fired, which capability it implicated, and when. The Mission Status
Response and introspection surfaces carry containment_version and
any containment annotations only to callers those profiles already
authenticate and authorize; this document adds no anonymous surface
and preserves the Status profile's anti-oracle posture
([I-D.draft-mcguinness-oauth-mission-status]). Containment Evidence
and the Protected Event Receipt both carry event detail (type,
source, event_id) and are audit material: a deployment retains and
discloses them under the same access rules as its other Mission
evidence, and SHOULD NOT copy event detail onto broader surfaces than
the audit trail requires. A rejected receipt additionally discloses
that a report was made and refused, which is itself incident posture
under the same rule.¶
This document registers two media types.¶
The containment_version member and any containment annotation ride
surfaces whose defining profile establishes no per-member registry
(the mission object of the Mission Status Response and the
introspection Mission projection,
[I-D.draft-mcguinness-oauth-mission-status]); consistent with those
surfaces' rules, a consumer ignores an unrecognized member.¶
This document requests registration of authority_contained in the
Mission Denial Reasons registry the expansion profile establishes
([I-D.draft-mcguinness-oauth-mission-expansion]), with its semantics
as defined in this document and Reference this document: it rides the
shared mission_denial_reason member that registry covers. The same string
also names a denial-reason identifier in the AuthZEN decision-context
classification set
([I-D.draft-mcguinness-mission-authzen]); that is a separate
specification-defined value space this document does not register
into, and the shared spelling implies no shared registration.¶
This document registers two media types per [RFC6838].¶
Type name: application¶
Subtype name: mission-containment-evidence+json¶
Required parameters: none¶
Optional parameters: none¶
Encoding considerations: binary; JSON encoded in UTF-8¶
Security considerations: see Section 21¶
Interoperability considerations: see this document¶
Published specification: this document¶
Applications that use this media type: Mission containment deployments¶
Fragment identifier considerations: same as for application/json¶
Additional information:¶
Person & email address to contact for further information: Karl McGuinness public@karlmcguinness.com¶
Intended usage: COMMON¶
Restrictions on usage: none¶
Author: IETF¶
Change controller: IETF¶
Type name: application¶
Subtype name: mission-protected-event-receipt+json¶
Required parameters: none¶
Optional parameters: none¶
Encoding considerations: binary; JSON encoded in UTF-8¶
Security considerations: see Section 21¶
Interoperability considerations: see this document¶
Published specification: this document¶
Applications that use this media type: Mission containment deployments¶
Fragment identifier considerations: same as for application/json¶
Additional information:¶
Person & email address to contact for further information: Karl McGuinness public@karlmcguinness.com¶
Intended usage: COMMON¶
Restrictions on usage: none¶
Author: IETF¶
Change controller: IETF¶
This document is part of the Mission-Bound Authorization for OAuth 2.0 set and defines the in-Mission narrowing complement to Mission Expansion's widening.¶