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
containment.transport_scope_violationMessage rejected for transport mismatch
containment.handshake_rate_limitedPer-sender rate limit triggered
containment.handshake_budget_exhaustedPer-correlation budget exceeded
containment.discovery_query_receivedAuthenticated card query received
containment.discovery_query_grantedFull card returned to authenticated requester
containment.discovery_query_deniedCard query denied

See Audit Trail — Event Types for the full list.