spec(auth): require buyer-principal credentials on transport channel; add CREDENTIAL_IN_ARGS#4057
Merged
Conversation
… add CREDENTIAL_IN_ARGS Buyer-principal credentials MUST arrive on the transport's authentication channel (Bearer per RFC 6750 §2, RFC 9421 signature headers, MCP/A2A auth framing per RFC 9728 §3, or mTLS) and MUST NOT travel in the task payload — top-level, in `context`, in `ext`, or any nested location. The spec was previously silent here, so storefront-shaped adopters kept independently rediscovering the smuggling vectors (top-level, then `context`, then `ext`). Adds a `CREDENTIAL_IN_ARGS` error code with `recovery: terminal` — auto-retry re-logs the credential on each attempt and is itself the prompt-injection exfiltration surface the rule closes. Sellers SHOULD reject under 3.1; upgrades to MUST 90 days after the 3.1 publication date. Carve-outs are explicit: `push_notification_config.authentication.credentials` is webhook receiver auth (orthogonal to the buyer principal); relay topologies (#2324) authenticate under the relay's own principal and MUST NOT forward buyer credentials in args. Closes #4046. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…credential-placement rule Per docs-expert review on PR #4057 — the threats-specific-to-agentic-advertising bullet about "prompt injection exfiltrating agent-side credentials" now points at the protocol-layer mechanism that closes the buyer-side instance of it (the credential-placement MUST/MUST NOT in authentication.mdx). One clause, no restructuring. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #4046.
The AdCP spec was silent on credential placement. Buyer-principal credentials arrive over the transport's authentication channel — Bearer (RFC 6750 §2), RFC 9421 signature headers, MCP/A2A auth framing (RFC 9728 §3), or mTLS — but nothing said credentials MUST arrive there and MUST NOT be embedded in the task payload. In practice that gap kept producing the same bug class: storefront-shaped adopters independently rediscovered top-level
<platform>_access_token, then nestedrequest.context.<platform>_access_token, thenrequest.ext.<platform>_access_token— three rounds of expert review on a single PR each surfacing a different smuggling vector.This PR adds a normative Credential placement section to
authentication.mdxafter the existing tenant-resolution paragraph and a newCREDENTIAL_IN_ARGSerror code.What changes
docs/building/by-layer/L2/authentication.mdx— new "Credential placement" section. Buyer-principal credentials MUST arrive on the transport's auth channel and MUST NOT live in args (top-level,context,ext, any nested location). Transport-agnostic; applies under every supported mechanism. Carve-outs explicit:push_notification_config.authentication.credentials— webhook receiver auth (orthogonal to the buyer principal).static/schemas/source/enums/error-code.json— addsCREDENTIAL_IN_ARGSto the canonical enum, withenumDescriptionsnarrative andenumMetadata.recovery: terminalper the dual-surface pattern. The wire-placement guidance follows the precedent set byCONFIGURATION_ERROR/AGENT_SUSPENDED— the code itself is the discriminator, noerror.detailsshape,error.fieldcarries the path that triggered detection (never the credential value or any prefix),error.messageis generic. Sellers MUST drop the smuggled credential from logs/audit/observability before persisting the rejection.docs/building/by-layer/L3/error-handling.mdx— addsCREDENTIAL_IN_ARGSto the Authentication and Access table and a one-paragraph cross-reference next to theAUTH_REQUIREDsub-cases warning, pointing back to the canonical rule inauthentication.mdx.Decisions on the open triage questions
Q1 — Error code (B chosen). New
CREDENTIAL_IN_ARGScode withrecovery: terminal. The wire-vs-application terminal/correctable mismatch onPERMISSION_DENIEDis exactly the foot-gun that bites SDK retry loops; the threat being credential re-logging, the cost of widening the enum is well-paid.Q2 — Seller rejection strength (B chosen). SHOULD reject under 3.1; upgrades to MUST 90 days after the 3.1 publication date. The security-reviewer's prompt-injection exfil concern is the same threat class
security-model.mdx#threats-specific-to-agentic-advertisingalready flags — weakening toMAYhere would contradict that page. The 90-day window gives implementations time to land detection without leaving credentials in LLM-visible payloads during migration.RFC anchors. Section cites RFC 6750 §2 (Bearer), RFC 9421 §2 (signed requests), and RFC 9728 §3 (protected-resource metadata) so the rule reads transport-agnostic, not bearer-token-specific.
Spec home.
authentication.mdx(after the tenant-resolution paragraph at L106), per the protocol-expert recommendation.error-handling.mdxcarries the table row + cross-reference only.Test plan
static/schemas/source/enums/error-code.jsonparses as valid JSON.node scripts/lint-error-codes.cjs— clean (62 canonical codes scanned across 83 storyboards).node scripts/build-schemas.cjs— generated manifest now reports 62 error codes.node scripts/lint-schema-links.mjs --check— clean.node scripts/check-owned-links.js— clean.🤖 Generated with Claude Code