Docs / Security

Security.

The honest version: where the risks live, what we mitigate, what we explicitly do not.

Threat model.

Settle is a non-custodial payment rail. The router contract receives the customer’s tokens and atomically forwards 99.5% to the merchant and 0.5% to the treasury. We protect against:

  • Drainer signatures. Customers sign ERC-3009 / EIP-2612 messages tied to a specific recipient and amount with a 5-minute deadline. There’s no open token approval to harvest.
  • Wrong-recipient settlement. Payout addresses must be verified by signing a challenge with the same wallet. We never route to an unverified address.
  • Sanctioned counterparties. OFAC screening at merchant onboarding (payout) and at customer wallet-connect (payer).
  • Compromised API keys. Auto-rotation every 90 days, immediate revoke from dashboard, scoped publishable keys for the frontend.
  • Replay of paid invoices. Invoice ids are unique; the router refuses a second payInvoice call with the same id.

We do not protect against:

  • The customer changing their mind. Settlement is final. There is no refund mechanism. See Settlement.
  • Compromised merchant wallets. If the wallet you registered as your payout address is drained, that is on the wallet — Settle has no key in the path.
  • Phishing the merchant’s GitHub OAuth. Auth is GitHub-only, so your Settle account is exactly as safe as your GitHub account. Use a hardware key on GitHub.

OFAC screening.

Two automated checks. No human review.

  1. At merchant onboarding — payout address is screened against OFAC SDN and the Chainalysis sanctions API. A hit rejects signup.
  2. At customer wallet-connect — payer address is screened before the pay button is enabled. A hit means the checkout page refuses to load, before any signature is requested. Funds never move.

Each check is ~$0.01 and cached per address. We do not screen on the customer’s name, email, or country — only on the on-chain address that would receive or send funds.

API key model.

Stripe-style split.

  • sk_live_…, sk_test_… — secret keys. Server-side only, full power. Treat like a database password.
  • pk_live_…, pk_test_… — publishable keys. Origin-bound to your verified domain. Can only call create_invoice and get_invoice. Safe to ship in your frontend bundle.

Key rotation.

Live keys auto-rotate every 90 days. There is a 7-day grace window where the old key and the new key both work, so you can update env vars without downtime.

If you connected via the Vercel or Netlify integration, the new key is delivered automatically; we update your env var on your behalf. For platforms without an integration we email the dashboard owner 14 days before rotation, then 1 day before, then on the day. Manual rotation is one click in the dashboard or one MCP call to create_api_key + revoke_api_key.

We fire key.rotated on every rotation and key.suspicious_use if the same key is used from an unusual IP / user-agent pattern.

Treasury & router.

The live router on Base is owned by a 2-of-3 Safe multisig. Signers are the founder, cofounder, and a cold backup signer. The same ownership model will apply to additional chains as they ship.

Every admin action goes through a 48-hour public timelock. Fee adjustments, treasury recipient changes, contract upgrades, and the pause function all require queueing the action publicly, waiting 48 hours, then executing. If we ever propose something questionable, the on-chain queue gives you 48 hours to react before it lands.

The pause function is gated by the same multisig and is intended for security incidents only. A pause stops new payInvoice calls; in-flight settlements that already mined are unaffected (settlement is atomic — there’s no in-flight state).

Source & disclosure.

Router source is published at github.com/settleco/contracts and is static-analysis-clean — Slither, Mythril, and Aderyn run in CI on every commit and currently report zero findings. We have not commissioned a paid external review; if and when we do, the report will be published next to the source. We disclose bugs publicly within 24 hours of patch deploy. The pause function gives us a window to deploy a fix without leaving merchants exposed.

Bug bounty program at security.settle.xxx. Payouts up to $250,000 USD-equivalent, paid in USDC on Base.

Anti-abuse limits.

  • Hard cap of $500,000 USD-equivalent per transaction. Set in the router. Larger sales must split into multiple invoices.
  • Rate limits on the REST API: 100 req/s per key, burst 200. The 429 response includes a Retry-After header. Ask if you need more.
Was this helpful?