carlos / platform Public

tenant email spec: the SNS trust anchor is the pinned HTTPS fetch, not a chain build

Second correction to the same paragraph, and this one reverses the first.
Requiring the fetched certificate to verify against system roots is
impossible against the real wire format: AWS serves exactly one cert in
SimpleNotificationService-*.pem — the bare leaf — and its issuer is an
intermediate distributed via AIA, which Go's x509.Verify never fetches.
Review proved it against a real captured PEM; the requirement as written
would have refused every genuine SNS message.

The anchor is https to a region-pinned sns.<region>.amazonaws.com host with
redirects refused, plus a subject assertion as defence in depth. The HTTPS
client validates AWS's TLS chain against system roots at the layer where
that check actually works.

Also records that the host pin must not leave the second label free —
sns.s3.amazonaws.com is the published sns-validator bypass shape.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev 5c3b317d7f035e08306895245f8adac60c207cb8 parent d66135b
1 file changed, +22 −5
  • docs/superpowers/specs/2026-08-19-tenant-email-design.md +22 −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 f2eda5eeb..2a3d05a25 100644
--- a/docs/superpowers/specs/2026-08-19-tenant-email-design.md
+++ b/docs/superpowers/specs/2026-08-19-tenant-email-design.md
@@ -449,11 +449,28 @@ Two security requirements, both non-negotiable:
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.
+- **The trust anchor is the pinned HTTPS fetch, NOT a chain build over the
+ returned PEM.** **CORRECTED 2026-08-19, second time**: an earlier version
+ of this section required verifying the fetched certificate against system
+ roots. That is impossible against the real wire format and would have
+ refused every genuine message. AWS serves exactly ONE certificate in
+ `SimpleNotificationService-*.pem` — the bare leaf, no intermediate — and
+ its issuer (`Amazon RSA 2048 M0x`) is an intermediate distributed through
+ the leaf's AIA extension, which Go's `x509.Verify` never fetches. Proven
+ against a real captured PEM; every reference validator (aws-sdk-ruby,
+ go.sns, AWS's own documented `openssl` procedure) decodes one block and
+ builds no chain.
+
+ So the security comes from: **https** to a **region-pinned
+ `sns.<region>.amazonaws.com` host**, with **redirects refused**, and the
+ certificate's subject asserted to be `sns.amazonaws.com` as defence in
+ depth. The HTTPS client already validates AWS's TLS chain against system
+ roots — that is the chain check, and it happens at the right layer.
+
+- **The host pin must not leave the second label free.** `sns.<anything>.
+ amazonaws.com` accepts `sns.s3.amazonaws.com`, which is the published
+ `sns-validator` bypass shape and a bucket that exists. Pin to the
+ configured region exactly; fall back only to a region-SHAPED pattern.
- **`SubscribeURL` must be constrained to the same host shape.** It is
fetched after verification, so ordering is not the issue — an