Containment & Governance
The Containment extension hardens INK against abuse by adding transport-scoped delegation, discovery minimization and per-correlation handshake budgets.
Transport-Bound Authorization
Delegation tokens can be scoped to specific transport channels via the allowedTransports constraint on delegation hops. See Authorization Chains. Transport Scoping for the full specification.
Standard transport identifiers:
| Transport | Description |
|---|---|
ink_http | Standard HTTPS INK endpoints |
ink_ws | WebSocket connections |
extension_api | Browser/app extension API calls |
voice | In-app voice channels |
line_phone | PSTN telephony |
human_review_queue | Queued for human review |
Transport-bound authorization is enforced on both INK HTTP and extension API surfaces, a token scoped to ["ink_http"] cannot be used to call extension API endpoints and vice versa.
Messages arriving on a transport not in the token’s allowedTransports are rejected with transport_scope_violation.
Version-Gated Migration
- v0.3+ tokens (with
tokenVersionfield): omittedallowedTransportsdefaults to["ink_http"](least privilege) - Legacy tokens (no
tokenVersion): receive a permissive default of["ink_http", "extension_api", "voice", "line_phone"]during a 90-day migration window - After the migration window closes, legacy tokens are treated as v0.3+ (default to
["ink_http"]only)
Capability-Gated Discovery
Agent Cards support four visibility levels that control what unauthenticated requests can see. See Agent Card. Visibility for the full table.
When an agent’s visibility is network_only or capability_gated, unauthenticated GET /ink/v1/:agentId/agent.json returns a redacted card that confirms the agent exists and supports INK but strips all sensitive fields.
Redacted Card
The redacted card includes only:
agentId, identitydisplayName, human-readable namesupportsInk: true, protocol support flagdiscoveryMode: "authenticate_for_details", instructs the caller to authenticatevisibility, the card’s visibility levelupdatedAt, freshness timestamp
Capabilities, endpoints, keys, availability and profile data are all stripped.
Authenticated Query Flow
Denial reasons: unknown_requester, insufficient_trust, not_connected.
The difference between network_only and capability_gated:
network_onlygrants the full card to any authenticated INK peercapability_gatedfilters by relationship tier, only peers meeting a trust threshold receive the full card
Handshake Flood Resistance
Per-correlation budgets and per-sender rate limits prevent handshake amplification attacks. These limits are enforced on all handshake ingress paths (INK HTTP and extension API).
Sender Map Limits
The senders map that tracks per-sender state has a configurable cap (default 1000 entries). When the cap is reached, the least-recently-used sender entry is evicted to prevent memory exhaustion.
Per-Correlation Budgets
Each correlationId (handshake session) has bounded state:
| Limit | Default | Description |
|---|---|---|
| Max challenges | 3 | Maximum network.tulpa.challenge messages per correlation |
| Max transitions | 5 | Total state transitions (intent + challenges + resolution) |
| TTL | 24h | Maximum handshake duration (bounded by intent expiresAt if shorter) |
Terminal states: network.tulpa.rejection and network.tulpa.resolution are terminal, no further messages are accepted for that correlationId.
Per-Sender Rate Limits
Sliding window counters per sender DID:
| Limit | Default |
|---|---|
| Intents per minute | 10 |
| Handshake messages per minute | 30 |
Violation Behavior
The first budget violation for a given sender returns a typed rejection with a backoffHint:
{ "protocol": "ink/0.1", "type": "network.tulpa.rejection", "reason": "handshake_budget_exhausted", "backoffHint": { "retryAfterSeconds": 60, "backoffClass": "sender" }, "nonce": "<base64url>", "timestamp": "..."}Subsequent violations from the same sender are silently dropped, no response is sent, preventing amplification.
Containment Rejection Reasons
| Reason | Description |
|---|---|
handshake_budget_exhausted | Per-correlation budget exceeded |
counterparty_cooldown | Recipient broadly rate-limiting |
sender_rate_limited | Per-sender sliding window exceeded |
delegation_budget_exhausted | Delegation issuance limit hit |
transport_scope_violation | Transport not in delegation token scope |
See Error Codes for HTTP status mappings.
Governance Advertisement
Agents advertise containment parameters in their Agent Card’s governance block. See Agent Card. Governance.
Audit Events
Containment events are logged to the agent’s hash-chained audit log:
| Event | Description |
|---|---|
transport_scope_violation | Message rejected for transport mismatch |
handshake_rate_limited | Per-sender rate limit triggered |
handshake_budget_exhausted | Per-correlation budget exceeded |
discovery_query_received | Authenticated card query received |
discovery_query_granted | Full card returned to authenticated requester |
discovery_query_denied | Card query denied |
See Audit Trail. Event Types for the full list.