Skip to content

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:

TransportDescription
ink_httpStandard HTTPS INK endpoints
ink_wsWebSocket connections
extension_apiBrowser/app extension API calls
voiceIn-app voice channels
line_phonePSTN telephony
human_review_queueQueued 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 tokenVersion field): omitted allowedTransports defaults 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, identity
  • displayName, human-readable name
  • supportsInk: true, protocol support flag
  • discoveryMode: "authenticate_for_details", instructs the caller to authenticate
  • visibility, the card’s visibility level
  • updatedAt, freshness timestamp

Capabilities, endpoints, keys, availability and profile data are all stripped.

Authenticated Query Flow

Diagram

Denial reasons: unknown_requester, insufficient_trust, not_connected.

The difference between network_only and capability_gated:

  • network_only grants the full card to any authenticated INK peer
  • capability_gated filters 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:

LimitDefaultDescription
Max challenges3Maximum network.tulpa.challenge messages per correlation
Max transitions5Total state transitions (intent + challenges + resolution)
TTL24hMaximum 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:

LimitDefault
Intents per minute10
Handshake messages per minute30

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

ReasonDescription
handshake_budget_exhaustedPer-correlation budget exceeded
counterparty_cooldownRecipient broadly rate-limiting
sender_rate_limitedPer-sender sliding window exceeded
delegation_budget_exhaustedDelegation issuance limit hit
transport_scope_violationTransport 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:

EventDescription
transport_scope_violationMessage rejected for transport mismatch
handshake_rate_limitedPer-sender rate limit triggered
handshake_budget_exhaustedPer-correlation budget exceeded
discovery_query_receivedAuthenticated card query received
discovery_query_grantedFull card returned to authenticated requester
discovery_query_deniedCard query denied

See Audit Trail. Event Types for the full list.