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
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 ◄──── operatorEverything 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
| Route | Audience | Protection |
|---|---|---|
POST /api/resources/:id/invoke | agents | payment, not authentication |
/mcp | agents | payment, not authentication |
GET /api/resources, /health, /.well-known/agent-commerce | anyone | none — public by design |
GET /ready | operators | none, but a fixed vocabulary, never raw errors |
GET /api/receipts, /api/events, /api/events/stream | operators | server.adminToken, constant-time |
/acp/checkout_sessions… | agents | protocols.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;
Authorizationheaders and backend API secrets;- the
PAYMENT-SIGNATUREheader and raw payment payloads; - the
Agent-Authorizationheader, 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 asINPUT_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
| Limit | Value |
|---|---|
| request body | 256 KB, on both the HTTP routes and /mcp |
| backend response | 1 MB |
| concurrent MCP tool calls | 8, plus a queue of 64 — then GATEWAY_BUSY |
| Agent-Authorization header | 8192 bytes, checked before decoding |
| X-Request-Id | [A-Za-z0-9._:-]{1,64} |
| SSE subscribers | capped |
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-uncertainwith its transaction hash, and the resource is not delivered.
Report vulnerabilities privately as described in SECURITY.md.