Repository navigation
Hosted abuse prevention for open signups #75
Description
Background
app.sendlit.app has open self-serve signup, and we're about to invite public users, starting with creators leaving beehiiv. A hosted email sender with open signups is a magnet for spammers. One abusive account can burn shared reputation, get ESP connections suspended and put our payment account at risk.
Source: Jesse Hanley's anti-abuse checklist (shared by Marc Lou on X, 18 Oct 2026). Jesse Hanley is the founder of Bento/PostShiba.
Current status of each item, checked against main (7ce6795):
| # | Control | Status | Evidence |
|---|---|---|---|
| 1 | Require email verification at signup | Have | Better Auth emailOTP login/signup with a verification code (apps/api/src/auth/better-auth.ts:202-213) |
| 2 | Optional real-person check (e.g. Exa AI) | Missing | none |
| 3 | Block disposable/temp and free email providers | Missing | no blocklist code in apps/api/src |
| 4 | Rate-limit signup to ~3/day/IP | Partial | OTP limited to 3/60s (better-auth.ts:209-212), no daily per-IP cap |
| 5 | AI scan of templates/broadcasts + auto-suspend | Missing | the suspend mechanism exists (teams.status = sending_suspended), but nothing triggers it |
| 6 | New-account send throttling for the first 30-60 days | Missing | only flat daily/monthly quotas (apps/api/src/delivery/quota.ts); no rate limit (#51) |
| 7 | Alert admins on big imports | Missing | import doesn't exist yet (#38) |
This blocks inviting public users to app.sendlit.app.
Proposed fix
Ship the controls below, hosted-only and feature-flagged so self-host is unaffected:
- 1. Email verification at signup (already in place, emailOTP)
- 2-4. Signup guards: real-person check, disposable/free email policy, about 3 signups/day/IP. See Signup guards for hosted: block disposable/free emails, cap signups per IP per day, optional real-person check #71
- 5. AI content scan + auto-suspend. See AI spam/phishing scan of templates and broadcasts with auto-suspend (hosted) #72
- 6. New-account send throttling. See New-account send throttling: spread sends over the day for the first 30-60 days (hosted) #73 (related: Per-ESP send-rate limiting (e.g. SES max send rate) #51, Day-one warm-up answer: warm-up guide and self-serve daily send caps for new domains / SES accounts #67, Warmup scheduler #5)
- 7. Large-import admin alerts. See Alert admins on large contact imports for review (hosted) #74 (ships with CSV contact import and export #38)
Also related: #65 (Acceptable Use / anti-spam policy, which gives us the right to suspend) and #25 (auto-pause on high bounce/complaint rates).
Acceptance criteria
- Signup guards for hosted: block disposable/free emails, cap signups per IP per day, optional real-person check #71 done (signup guards)
- New-account send throttling: spread sends over the day for the first 30-60 days (hosted) #73 done (new-account throttling)
- AI spam/phishing scan of templates and broadcasts with auto-suspend (hosted) #72 done (content scan + auto-suspend)
- Alert admins on large contact imports for review (hosted) #74 done before or together with CSV contact import and export #38 (CSV import)
- An AUP that allows suspension is published (Terms and Privacy pages on sendlit.app are empty; add Terms, Privacy, Acceptable Use / anti-spam policy and DPA #65)
- Admins have one place to see flagged signups, held broadcasts, large imports and suspended teams
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
clbotdev commentedon Oct 22, 2026
All acceptance criteria are met:
bun scripts/abuse.ts queue(apps/api/src/abuse/operator-cli.ts) lists open flags (signups, held emails, large imports), suspended organizations and paused teams;release/confirm/suspend-orgact on them.