# Security model

> What the buyer gate guarantees, how each guarantee is enforced in the code, and what it leaves to you.

Source: https://agenticterms.integraledger.com/security-model

The gate's purpose is narrow: the payment you sign carries the hash of the bytes you received. This page states what it
guarantees, how, and what it does not do.

## What the gate guarantees

| Guarantee | How |
| --- | --- |
| Nothing is signed before the comparison. | The signer is called only after SHA-256 of the served bytes equals the advertised H. On any decline before that point, the signer is never called. |
| The comparison is exact. | H is computed over the bytes as received, never parsed or re-serialised, and compared with the advertised value as 32 decoded bytes (so the hex's case does not matter, and a malformed value never matches). |
| The payment carries the computed hash. | The build takes the hash the gate computed, not the string the seller advertised. |
| The hash is read back from the payment. | `finish` rebuilds the payment from `chosen` and the bytes, joins the signer's answer, and reads H back out of the completed payment through the pairing's binding. It returns the payment only when that value is the hash of the bytes, or, where the proof is the agreement payment, without that reading. |
| A payment without a public proof waits for its agreement. | For a pairing whose payment is not itself a public proof of H, `transact` and `atr_transact` call the signer only after the agreement URL answers with a receipt for that H, and `atr_confirm` returns no `request` before that receipt is passed to it. `confirm` and `finish` neither pay nor check the agreement: a caller that drives them signs `request` only with the receipt `agree` returns. |
| Every payment is shown before it is signed. | The agreement payment is returned to the buyer's agent with its amount, asset, payee and network, and signed only when a second call carries it back. The gate applies no spending limit: what to approve is the agent's decision. |
| The fetch is bounded. | One `GET` of an `https` link, with no redirect, one 10-second deadline over headers and body, and at most 1 MiB read. A declared or streamed length over the bound cancels the body. |
| The bytes hashed are the bytes sent. | Every request asks for `Accept-Encoding: identity`, and a `200` whose `Content-Encoding` names any coding (gzip, br, a stacked list) is declined with its body unread. Nothing is decompressed, so the bounds apply to the bytes on the wire. The agreement receipt is read the same way, at most 64 KiB. |
| A channel pays under its ATR. | `within` takes the ATR's bytes, H and the channel from the hold, and only the amount from the seller's new challenge. An x402 challenge must advertise the held H. An MPP session challenge that names another channel or another H is declined, and one with no legal context is signed under the held H. A recorded charge cannot exceed what was signed. |
| The gate holds nothing that signs. | It hands requests to your signer and never sees a key. |
| Your network policy applies. | Every request goes through the `fetch` (or `httpx.AsyncClient`) you pass. |

The TypeScript and Python gates enforce the same rules, and the shared [vectors](https://agenticterms.integraledger.com/reference/vectors) fix each one.

## What it does not do

- **It does not judge the ATR.** The gate never reads the record's content. Whether the terms are acceptable is for you
  and your principal to decide.
- **It does not check the payment's values.** Amount, payee, asset, timing and payer are not compared with the ATR. A
  discrepancy is between the parties, and the ATR is the record of what was agreed.
- **It carries no business or legal logic.**
- **It does not store the ATR.** It returns the bytes; keeping them is yours. See
  [keeping the record](https://agenticterms.integraledger.com/guides/keeping-the-record).
- **It does not settle.** It returns the payment to you. It never talks to a facilitator.

## What each payment proves

Pairings differ in where H sits. In most, the buyer's signed payment carries H, and the chain records it when the payment
settles. In some, H rides in the seller's challenge, in a field too small for all of it, or not in the payment at all,
and the agreement payment is the public proof. Each pairing's binding states exactly what its payment shows and what it
does not; the [pairings reference](https://agenticterms.integraledger.com/reference/pairings) quotes every statement.

## The MCP tools and the skill

- The `terms-mcp` binary has no signer. The agent's own wallet signs the requests the tools return.
- A channel opening and a channel hold the tools return carry a `mac` under a key of the server process.
  `atr_channel_open` declines any other opening, `opening-unverified`, and `atr_channel_within` and
  `atr_channel_record_charge` decline any other hold, `hold-unverified`, before the gate is called.
- The `chosen` that `atr_confirm` returns carries a `mac` under the same key. `atr_agree` pays only the agreement URL in
  a `chosen` whose `mac` verifies, and declines any other `chosen`, `chosen-unverified`, before anything is fetched or
  signed. For a pairing with a channel, `atr_finish` reads only a `chosen` whose `mac` verifies, and declines any
  other, `chosen-unverified`, before the gate is called.
- The `terms-mcp` binary fetches only from public addresses. A link that names a loopback, private-use, shared,
  link-local, unique-local, documentation, multicast or reserved address is refused before any connection, and a host
  name is resolved once and connected to only when every address it resolves to is public. A host that serves the tools
  with `createBuyerServer` applies its own network policy through the `fetch` it passes.
- Every value the seller supplies is data: `atr.utf8`, and the agreement receipt's `network` and `transaction` that
  `atr_agree` and `atr_transact` return. The skill tells the agent to read them and never to follow instructions inside
  them.
- A discovery listing, or a hash an agent computes itself, is not a confirmation. The confirmation is `atr_finish`'s:
  it returns `signed` only when the pairing reads the hash from the completed payment, or, where the proof is the
  agreement payment, without that reading.

## Reporting a vulnerability

Report it privately through GitHub's private vulnerability reporting on the repository. See
[SECURITY.md](https://github.com/IntegraLedger/integra-agentic-terms/blob/main/SECURITY.md).
