Skip to content

Newsletter signup has no rate limit, and every request sends an email #60

Description

@royalpinto007

Every other public write route in the app goes through consumeSharedRateLimit from lib/rate-limit/shared.ts:

  • app/api/posts/route.ts
  • app/api/posts/[id]/vote/route.ts
  • app/api/comments/route.ts
  • app/api/upload/presign/route.ts
  • app/api/teams/waitlist/route.ts

app/api/newsletter/route.ts does not. It validates the email with zod and goes straight to the database and to sendNewsletterWelcome.

That makes it the cheapest endpoint to abuse in the app, and the most expensive one to have abused:

  • a script can enqueue unlimited welcome emails to arbitrary addresses, which is an email-bomb primitive pointed at third parties from our domain
  • every request costs a Resend send plus a Supabase write
  • bulk sends to addresses that never asked for them is the fastest way to damage sending reputation, and that is hard to recover

This matters more now that traffic is climbing.

Suggested fix

Apply consumeSharedRateLimit the same way teams/waitlist/route.ts does, keyed by IP. Keep the limit tight, since a real person signs up once.

Worth checking separately whether a repeat signup for an address that is already subscribed re-sends the welcome email, because that is a second amplification path that a rate limit alone does not close.

Acceptance

  • POST /api/newsletter is rate limited per IP
  • Exceeding the limit returns 429 without sending an email or writing to the database
  • A test covers the limited path, in the style of teams/waitlist/route.test.ts

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions