Security

How Stamp0 holds provider credentials, what it can and cannot do in your AWS or Cloudflare account, and how it decides which inbound mail to trust.

Stamp0 runs on your own provider account, so two questions matter most: what could Stamp0 (or someone who breached Stamp0) do in your account, and how does Stamp0 know an inbound message is real. This page answers both, for each provider.

Provider credentials

Amazon SES

Stamp0 stores no AWS keys. Your CloudFormation stack creates a role that trusts only Stamp0's platform role, and only with your connection's external ID; Stamp0 assumes it for each call. What the role may do is listed under What the role may do. Delete the stack to revoke access at once.

Cloudflare

Cloudflare has no cross-account roles, so Stamp0 holds an API token. Access is split so that the token Stamp0 keeps cannot run code in your account (two tokens):

  • The runtime token is stored encrypted with AES-256-GCM under a key ring kept outside the database. Each ciphertext is bound to its organization, connection and purpose, so it cannot be moved to another connection or column and still decrypt. Stamp0 shows only its last four characters, never returns it from the API, and keeps it out of logs and telemetry.
  • The setup token, which can deploy code, is held encrypted for at most one hour while a change you asked for runs, then deleted. It never enters a job payload or a log.
  • Every call to Cloudflare goes only to api.cloudflare.com and your account's R2 endpoint, and redirects are refused. Ids taken from Cloudflare responses are validated before they are used in a path.
  • On verification, and whenever you replace it, Stamp0 checks that the runtime token cannot upload a Worker and refuses one that can. If Cloudflare rejects the token (401 or 403), Stamp0 drops it from memory and the connection shows credential_invalid.

What the runtime token can still do. Cloudflare has no narrower permissions for these, so the stored token keeps:

  • Queues Write on the whole account. It is needed to pull from Stamp0's queue, and could also delete or change your other queues.
  • Email Sending Write on the whole account. It could send from any sending domain onboarded in the account, not only Stamp0's.

Stamp0 limits what it does with them: it only touches resources recorded on the connection, a From address must be on a domain the connection onboarded, and a sending domain or receiving name can be claimed by only one Stamp0 connection across all organizations. If you would rather not accept this, keep other queues and sending domains in a separate Cloudflare account. To revoke access, delete the runtime token in Cloudflare.

What Stamp0 runs in your account

  • SES: no code. The stack creates a role, a configuration set, EventBridge rules and a bucket.
  • Cloudflare: one Worker, which stores inbound mail and nothing else (no MIME parsing, no dependencies, no calls that Stamp0 waits on). It is built reproducibly and signed; Stamp0 refuses to deploy a bundle whose hash or signature does not match the release, never upgrades it without your setup token, and reports a Worker changed outside Stamp0 as modified. Removing the connection deletes only what Stamp0 recorded creating, and keeps your mail bucket.

Inbound mail

The rule for both providers: recipients and verdicts come only from a notification Stamp0 can authenticate, never from the stored message or its headers. A message's To: header can say anything; the envelope recipient Stamp0 routes on cannot be forged this way.

Inbound on SES

SES stores the raw message in your bucket and sends an SNS notification signed by AWS. Stamp0 checks the signature and the topic before it reads anything, takes recipients and SES's spam, virus, SPF, DKIM and DMARC verdicts from the notification, and only then reads the stored object.

Inbound on Cloudflare

Cloudflare has no signed inbound notification, so Stamp0's Worker produces one:

  1. For each recipient, the Worker gives the message a random id, stores the raw bytes in your R2 bucket, and writes a pointer: the id, the envelope recipient (RCPT TO), the object key, its SHA-256 and size, and the verdicts. The pointer is signed with HMAC-SHA256 under a key unique to the connection, which only the Worker and Stamp0 hold.
  2. The pointer is stored with the object and sent to the queue in your account. A best-effort "doorbell" request tells Stamp0 to pull now; it carries no mail and is authenticated with its own token.
  3. Stamp0 pulls the queue, rejects any pointer whose signature or connection does not match (bad_signature), re-reads the object and rejects it if its SHA-256 differs (object_tampered), and ignores a replayed pointer.
  4. A message is delivered only to inboxes on domains whose receiving connection is this connection, so another tenant, or another connection of yours, cannot route mail into your inboxes even with access to your Cloudflare account.

The trust anchor is weaker than SES's: "Cloudflare runs the Worker version Stamp0 deployed, and only it and Stamp0 hold the signing key", rather than a signature by the provider itself. The checks above, a fail-closed recovery sweep and key rotation keep it narrow:

  • Key rotation. Pointers name their key. When the key is rotated (with a setup token), pointers signed with the previous key are accepted for 31 days, longer than the queue and bucket keep them, then the previous key is dropped.
  • Nothing unsigned is processed. An hourly sweep re-reads stored objects to recover mail whose queue message expired during an outage, but only objects that carry a valid signed pointer; anything else is counted and left alone.
  • Durability. The queue keeps messages for 14 days with up to 100 delivery attempts, and the dead-letter queue is drained automatically, so a Stamp0 outage of hours does not lose mail Cloudflare accepted.

Verdicts on Cloudflare. Cloudflare rejects mail that fails both SPF and DKIM, or fails an enforcing DMARC policy, before the Worker runs. For the rest, Stamp0 reads the topmost Authentication-Results header that Cloudflare's own servers (mx.cloudflare.net) add to the raw bytes, ignoring copies a sender may have planted lower down. Threading by subject trusts a sender only with a DMARC pass and a DKIM pass aligned with the From domain. The spam score is stored as reported; there is no virus verdict.

Reporting a vulnerability

Email hello@stamp0.com with the details. Please do not test against other customers' data.

On this page