Core concepts

Security model

Trust boundaries, which routes are authenticated, and what the gateway deliberately does not defend.

Agent Commerce Gateway is not a payment processor, wallet, exchange or custodian. It never accepts, stores, derives or requires a merchant or buyer production private key.

Trust boundaries

text
       UNTRUSTED               SEMI-TRUSTED                  TRUSTED
  ───────────────────    ─────────────────────────    ────────────────────────
  agent input      ────► gateway process        ────► merchant backend
  payment proofs         validates all agent input,   administrator configured,
  authorization proofs   holds no keys                assumed to be yours
  protocol traffic
                         configuration          ◄──── administrator
                         environment            ◄──── operator

Everything from an agent is untrusted and validated. Configuration is trusted input — which is why backend URLs may only come from configuration.

Which routes are authenticated

RouteAudienceProtection
POST /api/resources/:id/invokeagentspayment, not authentication
/mcpagentspayment, not authentication
GET /api/resources, /health, /.well-known/agent-commerceanyonenone — public by design
GET /readyoperatorsnone, but a fixed vocabulary, never raw errors
GET /api/receipts, /api/events, /api/events/streamoperatorsserver.adminToken, constant-time
/acp/checkout_sessions…agentsprotocols.acp.auth.token, constant-time

With no server.adminToken configured, the operator routes return 404, not open data. Browser access is governed by server.allowedOrigins, an explicit allowlist that defaults to empty; agent traffic receives no CORS headers at all.

Secret handling

Never logged, never persisted, never returned:

  • private keys, seed phrases, mnemonics;
  • Authorization headers and backend API secrets;
  • the PAYMENT-SIGNATURE header and raw payment payloads;
  • the Agent-Authorization header, AP2 presentations and checkout JWTs.

Resolved ${VAR} values are never printed, even in configuration errors — errors name the variable, not the value.

SSRF and backend calls

  • Backend URLs are administrator configuration only. Agent input only fills {param} placeholders, URL-encoded, and never the scheme, host or port.
  • . and .. path parameters are rejected as INPUT_INVALID.
  • Redirects are not followed; a 3xx is a BACKEND_ERROR.
  • Every call has an explicit timeout and a 1 MB response cap.
  • The backend's error body is never relayed to the caller — only its status code.
There is no IP/CIDR allowlist. If you configure http://169.254.169.254/…, the gateway will call it. Treat configuration as privileged.

Denial of service

LimitValue
request body256 KB, on both the HTTP routes and /mcp
backend response1 MB
concurrent MCP tool calls8, plus a queue of 64 — then GATEWAY_BUSY
Agent-Authorization header8192 bytes, checked before decoding
X-Request-Id[A-Za-z0-9._:-]{1,64}
SSE subscriberscapped
There is no rate limitingA free resource is an unauthenticated proxy to your backend at whatever rate a caller chooses. Quotas and abuse controls belong in your API or your edge.

What the gateway does not protect against

  • It does not secure your backend — authentication and data protection stay yours.
  • It does not vet the buyer: no KYC, sanctions screening, fraud scoring or disputes.
  • It does not make payments reversible: no refunds, chargebacks or escrow.
  • It does not provide multi-tenancy, RBAC or policy controls.
  • It does not defend against a compromised host.
  • It cannot always tell whether a payment settled: an unconfirmed broadcast is recorded as settlement-uncertain with its transaction hash, and the resource is not delivered.

Report vulnerabilities privately as described in SECURITY.md.