Security & Compliance

Security first. By default.


Every default in squibble/email assumes the agent's token is already breached. This page documents how the system is built to keep that assumption survivable.

01 Threat Model

An autonomous agent is, by construction, a programmable adversary that already holds your email credentials. Squibble/email is designed around one assumption: the token will leak. Every other defense is in service of making that single failure mode non-catastrophic.

We do not protect against the agent itself acting with full intent. We protect against the blast radius when the agent is compromised, prompt-injected, or its token is exfiltrated through any channel — log files, error messages, an unrelated dependency.

  • In scope: token theft, credential reuse, sender spoofing, recipient leakage through logs, replay attacks, suppression-list bypass, send-quota exhaustion.
  • Out of scope: recipient-side phishing detection, content classification, recipient mailbox security, DMARC alignment for domains we do not control.

02 Token & Authentication Model

All API access is authenticated via Bearer JWTs that conform to RFC 7519. Each token encodes:

  • Mailbox binding — exactly one mailbox per token. The token cannot be redirected to read or send from a different mailbox.
  • Scoped actionsmessages:send, messages:index, attachments:show. A send-only token cannot read inbox; a read-only token cannot send.
  • JTI (JWT ID) — a unique identifier per token. Operators revoke a single token by its JTI in one CLI call; no key rotation, no other tokens affected.
  • Issuer + audience — every token is signed by Squibble's issuing key and validated against the API audience claim on every request.

Calling an endpoint outside a token's scope returns 403 with an RFC 9457 Problem JSON body. No silent drops, no partial executions.

One token. One mailbox. One verb list. Compromise revokes in a single call.

03 Sender Binding (Anti-Spoofing)

Even if a token is exfiltrated, it cannot be used to spoof an arbitrary sender. On every POST /api/v1/messages/send:

  • From is rewritten to the mailbox encoded in the token's claim.
  • Reply-To defaults to the mailbox unless explicitly overridden, and overrides are bounded by domain allowlist.
  • Envelope sender (MAIL FROM) is set to a VERP-encoded bounce address per RFC 3464 for authenticated bounce attribution.

A leaked token cannot send mail as anyone but the bound mailbox — the API has no surface for raw From: override.

04 Transport Security

Two transport boundaries are enforced fail-closed:

  • Client → API (HTTPS). TLS 1.2+ enforced at the edge (Traefik), HSTS preloaded, Let's Encrypt R12 certificates with automated renewal. Plaintext HTTP redirects to HTTPS; there is no plaintext API surface.
  • API → upstream SMTP (STARTTLS). Per RFC 3207, a failed STARTTLS upgrade aborts the SMTP session before AUTH. Plaintext credential exposure is structurally impossible — there is no fallback path that authenticates over plaintext.

The decision is binary at the edge: encrypted or no auth attempt. We do not surface a flag to relax this; relaxing it requires a code change.

05 Data at Rest

SMTP credentials for each onboarded mailbox are stored encrypted in Postgres using Fernet (AES-128-CBC + HMAC-SHA256, authenticated symmetric encryption). The encryption key is held in the API runtime environment, never committed to source, and decrypted credentials live in process memory only for the duration of a single dispatch.

Database backups are encrypted at the volume level and stored in the same Switzerland-resident infrastructure as the live database (see Jurisdiction). No customer SMTP credential leaves the EU/CH boundary at any point in its lifecycle.

06 PII Handling & Logging

Operational logs are redacted at write time, in line with GDPR Article 5(1)(c) data minimisation:

  • Recipient addresses are scrubbed from error_log records before persistence.
  • Message bodies are never logged in their entirety; only structural metadata (size, content-type, content-disposition) reaches the log stream.
  • Tokens are never logged. Authorization headers are stripped at the access-log layer.
  • Idempotency keys are stored as opaque strings and hashed before reaching durable storage.

Engagement events (opens, clicks) record the message UUID, event type, and timestamp — never recipient email or IP beyond what is required to fulfill the redirect.

07 Idempotency

Following the same pattern Stripe established for payment APIs, the Idempotency-Key header makes /messages/send safe to retry. The same key + same payload returns the original response for 24 hours without double-sending. Same key + different payload returns 409 Conflict — replay detection, not silent overwrite.

This protects against partial-failure retry storms during agent recovery loops, where a network partition can otherwise cause the same email to be sent dozens of times.

08 Suppression & Bounce Handling

Bounces are classified using RFC 3463 enhanced status codes. Permanent failures (5.x.x) are added to the suppression list immediately; transient failures (4.x.x) remain retryable. Unsubscribes via RFC 8058 one-click are honoured at the same priority. Suppression is per mailbox, not global — each mailbox owns its own list.

Sending to a suppressed address returns 422 with the suppressed recipients enumerated in the response body. We do not silently drop suppressed recipients from a multi-recipient send; the entire request is rejected so the caller cannot mistake a partial success for a full one.

09 Jurisdiction & Compliance

Squibble GmbH is a Swiss company (Kemptthal, Zürich) and the squibble/email infrastructure is hosted in Switzerland. All customer data — mailbox credentials, message metadata, suppression records, idempotency cache — resides under Swiss jurisdiction and is governed by the Swiss Federal Act on Data Protection (revFADP, in force since 1 September 2023).

For customers in the EU, Switzerland is recognised by the European Commission as providing an adequate level of data protection under GDPR Article 45. Personal data flows from EU controllers to Squibble do not require additional safeguards (SCCs, BCRs).

  • Data residency: Switzerland (CH).
  • Hosting jurisdiction: EU/EFTA only. No US-based subprocessors hold customer data at rest.
  • Lawful basis: contract (GDPR Art. 6(1)(b)) for customer data; legitimate interest for operational logs.
  • DPA available: we sign a standard Data Processing Agreement on request — contact below.

10 Vulnerability Disclosure

We accept and welcome security reports from the community. If you believe you have found a vulnerability in squibble/email, please report it privately rather than disclose publicly:

  • Email: security@squibble.ch
  • Acknowledgement window: within two business days.
  • Triage & remediation: we aim to validate within five business days and ship a fix within thirty days for non-critical findings; sooner for confirmed critical issues.
  • Safe harbour: good-faith research that respects user privacy and avoids destructive testing will not be pursued legally. Do not access data that is not your own; do not run automated scanners against the production API without prior coordination.

For DPA requests, GDPR Article 15/17 enquiries, or compliance questions: hello@squibble.ch.

Want early access?

Join the waitlist and we'll provision your mailbox and first JWT. Most teams ship their first email within a business day of onboarding.