Key management
- Do not commit
SPONSOR_SECRET_KEYto any repository or config bundle. - Load it from a secret manager (AWS Secrets Manager, GCP Secret Manager, Vault, doppler, sops).
- Rotate on a schedule (see Runbook).
- The sponsor account should hold only what is needed for fee sponsorship. Move excess XLM to a cold treasury address on a schedule.
Admin surface
Several endpoints (DELETE /discovery/resources/:id operator override, /admin/*) require an admin bearer.
- Set
ADMIN_TOKEN_HASHto a bcrypt hash of a strong secret. Empty means no admin surface, not open admin. - Restrict admin routes to a private network in your ingress.
- Log every admin call with the operator identity.
Rate limits
- Default
RATE_LIMIT_RPM=600is per source IP. Behind a load balancer, setTRUST_PROXY=trueso the limiter sees real clients. - Verify traffic is bursty; consider a separate, higher limit for
/verifythan for search endpoints.
Origins and CORS
ALLOWED_ORIGINS=*is fine for the discovery endpoints. It is not fine for admin endpoints, and they should not be reachable from the browser regardless.- Serve the facilitator on its own hostname, not as a path under your main app, so cookie scope stays clean.
Transport
- HTTPS only. Terminate TLS at the ingress; the facilitator does not need its own certificate.
- HSTS enabled on the ingress.
Payload validation
The facilitator strictly validates every field in/verify and /settle. Do not add middleware upstream that mutates JSON bodies (e.g. removing “unknown” fields) — it will break signature verification.
What can go wrong if you skip this
- Leaked sponsor key: attacker drains XLM used for fee sponsorship. Not customer funds, but expensive and embarrassing.
- Open admin: attacker delists competitors from the Bazaar or force-merges duplicates.
- No rate limit: verify endpoint gets used as a Soroban RPC amplifier.
- Loose CORS on admin: same as open admin, from a browser.