You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Signup guards for hosted: block disposable/free emails, cap signups per IP per day, optional real-person check #71
app.sendlit.app has open self-serve signup. A shared-infrastructure email sender with open signup attracts spammers, and one bad account can damage everyone's deliverability and our ESP/payment standing. Source: Jesse Hanley's anti-abuse checklist (shared by Marc Lou on X, 18 Oct 2026).
Current state on main (7ce6795):
Email verification is already in place. Login and signup use Better Auth emailOTP (apps/api/src/auth/better-auth.ts:202-213), so an account can't exist without proving it owns the mailbox. databaseHooks.user.create.after creates the default org (better-auth.ts:173-178).
OTP rate limit is per minute only. It's rateLimit: { window: 60, max: 3 } (better-auth.ts:209-212). There's no daily cap on new-account creation per IP.
No disposable/temporary email or free-provider blocking. Searching apps/api/src for "disposable", "blocklist" or "temp mail" finds nothing.
No real-person check at signup.
Part of #75 (hosted abuse prevention umbrella). This blocks inviting public users.
Proposed fix
Block disposable/temp email domains at signup, using a maintained list (e.g. the disposable-email-domains dataset, refreshed regularly) in a Better Auth before hook on new-user creation. Optionally add MX checks.
Free providers (gmail.com, outlook.com, etc.): make blocking or flagging configurable. Default to flag for review and lower initial quota rather than hard-block, because many creators use Gmail. Make it hard-block on the Free plan if we choose.
Rate-limit new-account creation to about 3 signups per IP per day (Redis-backed, trusting x-forwarded-for only behind our proxy). Keep the existing per-minute OTP limit.
Optional real-person check:
On signup, enrich the email/domain via a people/company lookup (e.g. Exa AI).
Store a risk score on the org.
Low-confidence accounts start with sending disabled or a low cap until an admin approves.
Feature-flagged, off for self-host.
Acceptance criteria
Signups from known disposable domains are rejected with a clear message (tested)
Free-provider policy is configurable (allow / flag / block) and flagged accounts are visible to admins
A 4th new-account signup from one IP within 24h is rejected (tested; respects trusted proxy config)
Optional real-person/risk check runs on signup behind a flag and stores a score; high-risk orgs start sending-restricted
All guards are hosted-only and off by default for self-host
Verified-email requirement documented as already met (emailOTP)
Activity