Skip to content

Harden forward handler: SNS signature verification, rate limiting, atomic cap#11

Merged
sragss merged 1 commit intomainfrom
fix/security-audit-round-2
Feb 13, 2026
Merged

Harden forward handler: SNS signature verification, rate limiting, atomic cap#11
sragss merged 1 commit intomainfrom
fix/security-audit-round-2

Conversation

@sragss
Copy link
Copy Markdown
Contributor

@sragss sragss commented Feb 13, 2026

Summary

Security audit found 3 vulnerabilities in the forward handler. All fixed.

1. SNS notification forgery (HIGH) — Forward handler only checked TopicArn, not cryptographic signature. An attacker who knew the ARN could forge notifications to inject messages into any inbox or trigger arbitrary forwards.

Fix: Added sns-validator package. All SNS messages are now cryptographically verified against Amazon's signing certificate before processing. Forged POSTs get 403.

2. Catch-all open relay (MEDIUM) — A subdomain owner could set catchAllForwardTo to a victim's address, then external spam sent to *@attacker.x402email.com gets relayed through SES for free. Risks SES account suspension.

Fix: Rate-limit subdomain forwards to 200/hr. Each forward logged to SendLog with a synthetic [email protected] fromEmail for counting. Excess forwards are dropped with a log message.

3. Message cap race condition (LOW) — TOCTOU between count check and message create. Concurrent SNS notifications could exceed the 500 message cap.

Fix: Wrapped count+create in a Prisma $transaction for atomicity.

Test plan

  • Send email to [email protected] — should still be received (SNS signature valid)
  • Verify forged POST to /api/inbox/forward with fake TopicArn gets 403
  • Forward rate limit logged after 200 forwards/hr per subdomain

🤖 Generated with Claude Code

…omic cap

1. SNS signature verification (HIGH): Add sns-validator to cryptographically
   verify all incoming SNS messages before processing. Prevents forged
   notifications that could inject messages into any inbox or trigger
   arbitrary forwarding.

2. Subdomain forward rate limiting (MEDIUM): Cap at 200 forwards/hr per
   subdomain, logged to SendLog. Prevents catch-all abuse as an open relay
   for externally-originated spam.

3. Atomic message cap (LOW): Wrap count+create in a Prisma $transaction
   to prevent concurrent emails from racing past the 500 message limit.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@vercel
Copy link
Copy Markdown

vercel bot commented Feb 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
x402email Ready Ready Preview, Comment Feb 13, 2026 3:29am

const subdomainName = recipientDomain.replace(`.${DOMAIN}`, '');

// Rate-limit forwards per subdomain to prevent open relay abuse
const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rate limit check on line 253 is not atomic with sendLog.create() on line 287, allowing concurrent requests to bypass the 200/hr forward limit

Fix on Vercel

@sragss sragss merged commit 92be78c into main Feb 13, 2026
4 checks passed
@sragss sragss deleted the fix/security-audit-round-2 branch February 13, 2026 03:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant