Security
How senderZ protects API keys, tenant data, webhook secrets, and the operational surfaces of the platform — with honest signals about what is live today, what is in flight, and what is outside the product.
On this page
Encryption at rest and in transit
Every byte of traffic between your infrastructure and the senderZ API rides over TLS 1.3. Cloudflare terminates TLS at the edge and re-establishes encrypted channels to every origin worker. Inbound device webhooks travel through a Cloudflare Tunnel from the operator's dedicated Apple hardware, which is encrypted end-to-end before it reaches our public edge.
At rest, Cloudflare D1 provides platform-level encryption for the databases that hold tenant metadata, message records, and usage counters. On top of that, senderZ applies AES-256-GCM to the fields that would cause the most damage if leaked: tenant webhook secrets, OAuth access and refresh tokens for CRM integrations, and Bring-Your-Own-Key AI provider credentials. The encryption logic lives in workers/api/src/lib/ai-router.ts and is exercised in production since April 2026 (commits ab39cbc and 446548d).
HSM-backed key custody for the master AES key is on the roadmap Planned — Q4 2026. Today the master key is a Wrangler secret, rotated manually. HSM storage removes that manual step and reduces the blast radius if a Cloudflare account were compromised.
API key lifecycle
API keys are issued with a high-entropy secret plus a prefix (sz_live_... or sz_test_...). The raw value is shown exactly once at creation — after that, senderZ stores only the SHA-256 hash of the key (workers/api/src/middleware/auth.ts:19-29). A hash leak leaves an attacker no path to the live key: there is no salt because the input is already high-entropy, and there is no second-factor check because the key IS the factor.
Every request lands on the auth middleware first. The middleware hashes the bearer token, looks up the hash in D1 api_keys, and if found, sets the tenant context for the rest of the handler. If the key is revoked (active = 0), missing, or tied to an inactive tenant, the request is rejected before any business logic runs.
Rotation is voluntary today: customers can create a new key, cut over, and revoke the old one. We recommend 90-day rotation for production workloads. Scheduled rotation reminders in the portal Planned — Q1 2027 are on the roadmap.
Rate limits run per-key per-minute using Cloudflare KV as the counter store. The default is 60 requests per minute on Starter, higher on Growth and Scale, adjustable on request. Limits are explained in the Limits page.
Secrets management
Every secret senderZ runs on — ADMIN_API_KEY, INTERNAL_AUTH_SECRET, STRIPE_WEBHOOK_SECRET, ANTHROPIC_API_KEY, Clerk API keys, GitHub and Google OAuth secrets, the AI_ENCRYPTION_KEY master — is stored as a Wrangler secret on Cloudflare, encrypted at rest by the Cloudflare platform, and injected at runtime into the three senderZ workers (api, router, billing).
Secrets never enter source control. The repository's .gitignore excludes .env and .dev.vars. Pre-commit hooks scan for known secret patterns. Production secrets and development secrets are separate values; the worker environment variable manifests in each wrangler.toml name the binding, not the value.
Formal rotation procedure Planned — Q3 2026 — a documented, scheduled process for each secret (how often, who rotates, how to roll over without downtime). Today rotations happen on-demand in response to operational events.
Tenant isolation
Every tenant-scoped row in D1 carries a tenant_id column. Every SQL query on those tables must include WHERE tenant_id = ? — no exceptions. The assertTenantOwnership() helper in workers/api/src/guards.ts is called at the top of write paths to verify that the authenticated caller owns the resource they are trying to modify.
Phone pools, API keys, webhook secrets, opt-out records, consent logs, usage counters, Zapier subscriptions, CRM integration tokens, AI personas — every one of these is partitioned by tenant_id. There is no "global" senderZ row that crosses customers, and there is no admin override that reads data as a specific tenant without an explicit admin action logged against an operator identity.
Code review is the enforcement gate. A pull request that introduces a query on a tenant table without WHERE tenant_id is blocked by the code reviewer skill and cannot merge. Future static analysis in CI Planned — Q3 2026 will catch this at build time as well.
Authentication and authorization
senderZ has three independent authentication surfaces, each with its own threat model.
Customers use API keys (REST, SDK, MCP) or session cookies issued by Clerk after OAuth sign-in (developer and Simple Mode portals). Clerk handles password hashing, MFA, SSO, and account recovery — senderZ does not store credentials. Account linking by email is gated behind the identity provider's email verification signal (we always re-verify via /user/emails on GitHub OAuth, commit 446548d).
Operators (senderZ staff) use a distinct Admin API key, rotated on a different cadence than customer keys, and compared with a timing-safe equality check in the admin middleware. The admin key never leaves Noa's 1Password vault and the operator dashboard is the only surface that uses it.
Inter-worker calls (router calling billing for quota checks, device supervisor calling api for phone status) use a shared INTERNAL_AUTH_SECRET passed as an X-Internal-Secret header. This is not a substitute for tenant auth — it's a second layer that prevents public internet callers from reaching internal endpoints. Added as part of the April 2026 security audit (commit e41b9cf).
Vulnerability disclosure
Report security issues to [email protected]. We acknowledge within three business days. We coordinate responsible disclosure on a standard 90-day window — longer if the fix is materially complex, shorter if active exploitation is observed.
We do not currently offer a paid bug bounty Planned — Q1 2027. Researchers who report valid issues get public credit on this page (opt-out available), a thank-you from Noa, and a free year of the highest senderZ plan for their own projects.
We will not pursue legal action against researchers who act in good faith, test only their own accounts, avoid privacy violations and data destruction, and give us time to fix before publicizing.
Third-party audits
senderZ is a young company and we are honest about where we are on the audit path.
- External penetration test Planned — Q3 2026 Black-box and authenticated gray-box testing of the public API and portal. Report available under NDA after completion.
- SOC 2 Type I Planned — Q4 2026 Point-in-time attestation of our security controls. We are working toward this with Drata or Vanta (not yet selected).
- SOC 2 Type II Planned — Q2 2027 Six-month operating-effectiveness attestation after Type I.
- Internal security reviews Available on request We run internal code-review and audit cycles (most recent: April 2026, closing ten items) and can share summaries under NDA.
Frequently asked questions
What encryption algorithm does senderZ use at rest?
Sensitive tenant data including webhook secrets and OAuth tokens is encrypted with AES-256-GCM before being written to Cloudflare D1. Encryption keys are stored as Wrangler secrets and never in source code. Less-sensitive data (message metadata, usage counters) relies on Cloudflare D1's platform-level encryption at rest.
How often are API keys rotated?
API keys are SHA-256 hashed at creation and stored only as hashes — the raw value is shown once and never again. Customers can rotate keys at any time through the portal; old keys can be immediately revoked. We recommend rotation at least every 90 days for production workloads, but senderZ does not force rotation.
Where is my data stored geographically?
Customer data lives in Cloudflare D1, which replicates to the edge region closest to each read. Today senderZ runs in Cloudflare's global network without region pinning. EU-only data residency is planned for Q2 2027 and will be offered to enterprise customers who need it.
What happens to in-flight messages if an API key is revoked?
Revocation blocks new sends immediately — the auth middleware rejects the key on the next request with a 403. Messages already enqueued to Cloudflare Queues continue to deliver because the queue message carries a tenant_id and message_id, not an API key. This matches the at-least-once delivery guarantee.
Can one tenant read another tenant's data?
No. Every D1 query on tenant-scoped tables (messages, templates, webhooks, api_keys, contacts, campaigns) includes WHERE tenant_id = ?. The assertTenantOwnership() guard in workers/api/src/guards.ts enforces the same at the route-handler level for write paths. A code review gate blocks any PR that introduces a query without tenant filtering.
What is the SOC 2 status?
senderZ is not currently SOC 2 attested. SOC 2 Type I is planned for Q4 2026 and Type II for Q2 2027. Before attestation lands, we can share a security questionnaire response and our architecture documentation under NDA.
Who do I contact about a security vulnerability?
Email [email protected]. We acknowledge reports within three business days and coordinate responsible disclosure on a 90-day window. A formal bug bounty program is planned for Q1 2027.
Need something formal?
We share our DPA, SOC 2 status, security questionnaire responses, and other formal materials under NDA. Email us or request access below.