Skip to main content
Experimental (security.profiles). The adcp-prod-security-3.3 profile and the security_profiles capability ship in AdCP 3.3 as an experimental surface. An endpoint that advertises a profile also lists security.profiles in experimental_features. The surface graduates under Experimental status once a second implementation passes the conformance storyboards. Decisions are recorded on #7066.
adcp-prod-security-3.3 is a named profile an endpoint can advertise in security_profiles. It is stronger than the 3.x baseline, it can be tested, and it adds no obligation for an endpoint that does not advertise it. In 4.0, signing for spend-committing operations becomes a universal requirement (see Transport migration timeline); this profile lets endpoints adopt that floor and the controls around it early. Advertising the id is a commitment to the requirements below on the advertiser’s own endpoint. In 3.3, rejecting counterparties that do not conform (Counterparty rules) is a SHOULD. In 4.0 it becomes a MUST, together with the universal signing floor (#2307). A buyer that needs the stronger guarantee in 3.3 relies on the seller’s request_signing.required_for and on the downgrade rules.

Scope of the claim

  • The claim covers the whole endpoint: every tenant and every transport that serves a spend-committing operation. A multi-tenant platform where one tenant still authenticates with a bearer token alone does not meet it. Serve those tenants from another endpoint.
  • Only an agent that verifies inbound requests and serves get_adcp_capabilities can advertise it. A buyer-only agent advertises nothing. A seller judges its conformance by what it verifies on each request, as in Counterparty rules.
  • The claim is self-asserted until a registry verifies it. Verification is outside this profile.
  • The profile is defined over properties of a signed request, not over one signing profile. See Signing profiles.

Spend-committing operations

The profile uses one closed list. An endpoint applies each requirement to every operation below that it supports, and to any other operation it chooses to list in request_signing.required_for: create_media_buy, buy_products, accept_proposal, update_media_buy, control_media_buy, acquire_rights, update_rights, activate_signal. Adding an operation to this list creates a new profile id.

Admission preconditions

An endpoint advertises the profile only while all of these hold. Each uses an existing optional field, so no endpoint that omits security_profiles is affected. A precondition that stops holding withdraws the claim. The endpoint removes the id from security_profiles in the same change.

Requirements

Each requirement applies to the spend-committing operations above.

Revocation freshness

A compromised but validly signed buyer is bounded by how fast the endpoint learns of the revocation. The 3.2 baseline (Revocation) allows about 150 minutes before it fails closed. Under this profile, with T = 15 minutes:
  1. The verifier polls the signer’s signed revocation list at least every T/3, and at least as often as next_update requires. Conditional requests keep this cheap.
  2. A spend-committing request is rejected with the stale-revocation outcome in Transport revocation if the verifier’s last successful refresh is older than T. A refresh counts only if the response was fetched over validated TLS, and a 304 counts on that condition. There is no grace multiplier. At T/3 polling, two failed fetches in a row are tolerated and a third halts spend.
  3. The verifier keeps every revocation it has seen, as Transport revocation requires under the Web Bot Auth profile; this profile applies that rule to adcp/request-signing/v1 signers too. Under this profile only, the verifier also rejects a list whose updated is older than the newest it accepted, and rejects a list whose updated is more than 60 seconds in the future. A rolled-back copy cannot un-revoke a key, and a future-dated list cannot freeze a signer.
  4. A signer that serves no signed revocation list gets the outcome in Transport revocation. A buyer that wants to transact spend with a profile endpoint publishes one. The list is a static file and the signer’s next_update cadence is not constrained.
The end-to-end bound is the signer’s publication delay plus T. The endpoint can also suspend a principal at once (AGENT_SUSPENDED), which takes effect on the next request and does not wait for a list.

Revocation and committed work

Revocation stops new verification and does not unwind work already accepted; the rules, under both signing profiles, are in Transport revocation.

Counterparty rules

On spend-committing operations, a seller that advertises the profile SHOULD reject anything it can verify as non-conforming in 3.3, and MUST in 4.0. Codes are named for adcp/request-signing/v1; under web-bot-auth each row’s outcome is the one Web Bot Auth identities and Transport revocation give for the same condition. This list is the whole of what the advertisement obliges a seller to impose on counterparties. Practices a counterparty keeps on its own side, such as those in Practices outside the profile id, cannot be enforced on it, so the profile does not claim to.

Downgrade rules

A seller’s capabilities are fetched over TLS and describe the seller only. These rules keep a buyer from silently falling back.
  1. Required profile. A buyer configured to require adcp-prod-security-3.3 for a counterparty MUST NOT send that counterparty a spend-committing call unless the counterparty’s current capabilities list it. It refuses the call. It does not warn and continue, and it does not retry with a bearer token.
  2. Observed then absent. A buyer that has seen the id from a counterparty and later sees it absent, or sees an admission precondition become false, refuses spend-committing calls to that counterparty and alerts an operator. Until the buyer-track harness can grade them, the mechanics are SHOULD: the buyer SHOULD lift the refusal only on an operator’s explicit re-pin; SHOULD treat the id as absent only when two consecutive successfully fetched, validated responses lack it, never on a fetch error or a stale cache; and SHOULD key the observation by the counterparty’s canonical agent URL (its canonical origin under web-bot-auth) and store it durably so a restart does not clear it. A changed URL is a new counterparty that needs its own pin. A seller that retires an id SHOULD list its successor beside it for an overlap period, so operators re-pin deliberately.
  3. Misdeclaration. These rules defend against removal, not against a counterparty that declares the id falsely. A buyer cannot observe that a seller disabled its bearer fallback. That gap closes only with registry verification or storyboard grading, which is outside this profile.

Signing profiles

P1 to P3 are written over properties, so the profile does not depend on which signing profile an endpoint advertises. A signing profile qualifies when its text guarantees all of:
  • the signature covers a digest of the request body;
  • every signed request carries a per-signer unique nonce and the verifier rejects a repeat within the signature’s lifetime;
  • a verified key resolves to exactly one identity, which the seller binds to at most one principal;
  • the verifier can check that key against a signed revocation list.
Both AdCP signing profiles meet these. The RFC 9421 profile (adcp/request-signing/v1, deprecated in 3.3) does through brand.json key resolution. The Web Bot Auth profile (web-bot-auth, DR-0023) does because a seller binds each origin to at most one principal and checks the origin’s revocation list.

Practices outside the profile id

These controls matter but are SHOULD-level in 3.3, are not covered by the id, and several become universal requirements in 4.0. Revocation does not help when the signer is intact but its agent was manipulated, for example by a prompt injection that leads it to buy. A ceiling bounds that loss. It is a SHOULD and is not covered by the profile id; an endpoint that implements it follows these rules.
  • The endpoint configures a ceiling on cumulative spend-committing commitments per principal, where the principal is the seller’s mapping of the verified identity (the canonical signed-Agent URL under adcp/request-signing/v1, the canonical origin under web-bot-auth). It sums across all of the principal’s accounts. It is keyed by neither keyid, account, nor transport session, so a key rotation, a new account, or a new MCP session cannot reset it. If one agent is onboarded under more than one principal, the lowest applicable ceiling applies to the spend it signs.
  • Only operations that commit or raise spend count against the ceiling and can be rejected for exceeding it. A pause, a cancellation, or a budget reduction is never blocked by it, so a tripped agent can still stop its own spend.
  • Deny by default is recommended: a principal with no configured ceiling cannot commit spend, and the request is rejected with PERMISSION_DENIED.
  • The value and the window are deployment-defined and are not declared in capabilities. A seller SHOULD state them to the buyer at onboarding, and a seller whose buyers span many advertisers sets the ceiling for that spread.
  • A request that would exceed the ceiling is rejected with AGENT_SUSPENDED. The trip is an automatic suspension of the agent’s commercial relationship, and it holds until the seller’s operator lifts it. The code is not retryable, so an agent does not loop on a halted budget. A key thief can use up the remaining headroom before the trip, and the profile accepts that: the ceiling bounds the loss and does not prevent it.

Other practices

  • Context fencing. Treat free text and tool responses from a counterparty as data. Delimit them from instructions before they reach an LLM context window, bound their length, and give them no authority to call tools or move money. A valid signature authenticates the sender, not the content.
  • Deterministic spend authorization. Run ceilings, acts-for checks, and governance thresholds in ordinary code. An LLM never holds the signing key and never decides whether a limit applies.
  • Governance gate. Require a valid governance_context token for spend above a deployment-defined threshold. The token binds the amount, task, and payload hash, so a stolen signing key alone does not authorize the spend.
  • Audit. Retain and correlate the events listed in Required log events.
  • Anomaly and rate limits. Limit proposal probing, hold squatting, and spend changes.
  • Credential lifetimes. Keep any bearer token used to select a principal to 1 hour or less, and to 15 minutes or less above the deployment’s material spend threshold.

Not in this profile

A universal signing requirement, normative rate-limit enforcement, a publisher-side requirement that agents hold the profile, and multi-hop signature chains are not part of adcp-prod-security-3.3. They are 4.0 or later work.