carlos / platform Public

tenant email spec: pin the SNS cert host to sns.<region>, not the amazonaws.com suffix

Adversarial review of the ingest endpoint defeated the check as specified.
*.amazonaws.com includes every S3 bucket, API Gateway stage and Lambda URL,
so any AWS customer can serve an attacker's PEM from a host with a genuine
publicly-trusted certificate — reducing SNS signature security to the
secrecy of a topic ARN, which is an identifier, not a secret.

Adds the two requirements the original omitted: verify the fetched
certificate against system roots and check its subject, and constrain
SubscribeURL to the same host shape (review demonstrated it reaching
link-local metadata).

Also corrects this document's own label-awareness example, which was wrong:
a bare HasSuffix rejects sns.eu-west-1.amazonaws.com.evil.com. The case it
accepts is evilamazonaws.com.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev c3f2fd4c830af1143255fadaa43dd5c512017242 parent 10fa186
1 file changed, +27 −5
  • docs/superpowers/specs/2026-08-19-tenant-email-design.md +27 −5
diff --git a/docs/superpowers/specs/2026-08-19-tenant-email-design.md b/docs/superpowers/specs/2026-08-19-tenant-email-design.md
index 01e0c6c9e..f2eda5eeb 100644
--- a/docs/superpowers/specs/2026-08-19-tenant-email-design.md
+++ b/docs/superpowers/specs/2026-08-19-tenant-email-design.md
@@ -439,11 +439,33 @@ event destination onto a console endpoint (`POST /api/ses/events`).
Two security requirements, both non-negotiable:
- SNS **subscription confirmation** must be handled, or no events arrive.
-- The `SigningCertURL` **must be validated as an `amazonaws.com` host
- before it is fetched**. That check is the entirety of SNS signature
- security and it is the classic place to get it wrong: an unvalidated
- URL lets anyone who can reach the endpoint present their own signing
- certificate and forge every event below.
+- The `SigningCertURL` **must be pinned to SNS's own host before it is
+ fetched** — `sns.<region>.amazonaws.com`, NOT the `amazonaws.com`
+ suffix. **CORRECTED 2026-08-19 after review found the suffix form
+ exploitable**: `*.amazonaws.com` includes every S3 bucket, API Gateway
+ stage and Lambda URL, so any AWS customer can serve an attacker's PEM
+ from a host with a genuine, publicly-trusted TLS certificate. With the
+ suffix form, all that stands between a stranger and a forged event is
+ the topic ARN — an identifier that appears in IaC and logs, not a
+ secret.
+
+- **The fetched certificate must be verified against system roots and its
+ subject checked.** Pinning the host without validating the chain still
+ trusts whatever PEM comes back, and an open redirect under the allowed
+ host would walk the fetch off AWS entirely. Neither check is sufficient
+ alone; both are required.
+
+- **`SubscribeURL` must be constrained to the same host shape.** It is
+ fetched after verification, so ordering is not the issue — an
+ unconstrained URL is a blind SSRF that reaches link-local metadata, and
+ review demonstrated it doing so.
+
+- A note on what label-awareness actually buys, because the obvious
+ example is wrong: a bare `strings.HasSuffix(host, "amazonaws.com")`
+ does NOT accept `sns.eu-west-1.amazonaws.com.evil.com` — that string
+ ends in `evil.com`. The case it does accept is `evilamazonaws.com`,
+ with no separating dot. That is the lookalike the `.`-prefixed check
+ earns its keep against.
**Counts.** Events give per-app send, bounce, complaint and delivery
counts. Those counts are simultaneously the abuse signal and the **only**