Background
schemas/cache/core/push-notification-config.json (line 7-11) defines url as format: \"uri\" with no port restriction. The spec is silent on whether publishers may restrict destination ports.
Why it matters
SDKs implementing the publisher side need to decide whether to enforce a port allowlist on buyer-supplied URLs as defense-in-depth against SSRF (a buyer URL like https://internal.example.com:6379/ can smuggle traffic to internal Redis on the same routable IP, even when the IP-range check passes).
If SDKs implement port allowlists by default, they reject legitimate buyers on non-standard TLS ports — Tomcat default :9443, Spring Boot default :4443, path-routed multi-tenant gateways. If they don't, the SSRF guard is weaker.
The Python SDK's foundation audit (adcp-client-python#297 review) initially defaulted to {443, 8443} — the protocol-expert review flagged this as over-restriction, since the spec doesn't constrain ports. The fix: default permissive, expose DEFAULT_ALLOWED_PORTS as opt-in operator hardening.
Proposed fix
Add a single sentence to push-notification-config.json url description:
Publishers SHOULD NOT constrain the URL's port to standard HTTPS values (443, 8443) by default — buyers may legitimately host webhook receivers on non-standard ports (:9443 Tomcat, :4443 Spring Boot, path-routed multi-tenant gateways). Operators who want a hardened destination-port allowlist as defense in depth opt in explicitly; the default URL contract is unconstrained beyond the format: uri requirement.
Optional: also note in docs/building/implementation/security.mdx#webhook-callbacks that AdCP recommends {443, 8443} for hardened deployments — see related issue.
Why now
Locks the spec position so SDKs stop diverging on this. The Python SDK exports DEFAULT_ALLOWED_PORTS = {443, 8443} as opt-in hardening (adcp.signing.DEFAULT_ALLOWED_PORTS), aligned with what the recommendation should be.
Surfaced by Python SDK foundation audit on adcp-client-python#297.
Background
schemas/cache/core/push-notification-config.json(line 7-11) definesurlasformat: \"uri\"with no port restriction. The spec is silent on whether publishers may restrict destination ports.Why it matters
SDKs implementing the publisher side need to decide whether to enforce a port allowlist on buyer-supplied URLs as defense-in-depth against SSRF (a buyer URL like
https://internal.example.com:6379/can smuggle traffic to internal Redis on the same routable IP, even when the IP-range check passes).If SDKs implement port allowlists by default, they reject legitimate buyers on non-standard TLS ports — Tomcat default
:9443, Spring Boot default:4443, path-routed multi-tenant gateways. If they don't, the SSRF guard is weaker.The Python SDK's foundation audit (
adcp-client-python#297review) initially defaulted to{443, 8443}— the protocol-expert review flagged this as over-restriction, since the spec doesn't constrain ports. The fix: default permissive, exposeDEFAULT_ALLOWED_PORTSas opt-in operator hardening.Proposed fix
Add a single sentence to
push-notification-config.jsonurldescription:Optional: also note in
docs/building/implementation/security.mdx#webhook-callbacksthat AdCP recommends{443, 8443}for hardened deployments — see related issue.Why now
Locks the spec position so SDKs stop diverging on this. The Python SDK exports
DEFAULT_ALLOWED_PORTS = {443, 8443}as opt-in hardening (adcp.signing.DEFAULT_ALLOWED_PORTS), aligned with what the recommendation should be.Surfaced by Python SDK foundation audit on
adcp-client-python#297.