Repository navigation
Sign-in writes email addresses to the server logs and keeps unused sign-in tokens forever, and the privacy page says neither #450
Copy link
Copy link
Closed
Labels
bugSomething isn't workingSomething isn't working
Description
Needs your OK: this changes the privacy page's wording on logs and on how long sign-in records are kept. Swap pipeline:proposed for pipeline:ready to have it built.
What happens
Two things sign-in does aren't on the privacy page, and CLAUDE.md asks that the legal pages match the code.
- Email addresses in logs.
src/auth/config.tslogs{ email: identifier }with "magic link dispatched" for every sign-in email.src/auth/magic-link-rate-limit.tslogs{ email, ip, bucket }whenever a sign-in request is rate-limited.redact.pathsinsrc/lib/log.tscovers neitheremailnorip. The privacy page ("Logs and rate-limiting") says server logs are "standard request/error logs and do not include cookies, tokens, or magic-link URLs". It doesn't mention email addresses or IPs. - Unused sign-in tokens are never deleted. Auth.js stores a
verification_tokensrow (identifieris the email) for every sign-in link. The stock Drizzle adapter deletes it only when the link is used.runHousekeepinginsrc/jobs/housekeeping.tssweeps OAuth records, rate-limit windows and login codes (magic_links), but notverification_tokens. Every link nobody clicks, including links anyone can request for any address, stays in the table with that address. The privacy page says sign-in records are deleted by an hourly cleanup, which is true of the login codes only.
This affects organizers (and anyone whose address is typed into the sign-in form), and self-hosters who ship logs to a third party.
Fix, in outline
- Logs: log
emailDomain(the helperconfig.tsalready uses for the activity row) instead of the address in both log calls. Keep the IP in the rate-limit warning only if the page says so; dropping it is simpler. - Retention: add a sweep that deletes
verification_tokensrows whoseexpiresis in the past, next tosweepExpiredLoginCodes. Call it fromrunHousekeepingand include its count in the return value and log line, as the other sweeps do. - Privacy page: in
src/app/(legal)/privacy/page.tsx, add "email addresses" to what logs don't include (or say what they do include), name both sign-in records in the hourly-cleanup sentence, and bump "Last updated".
Watch for
emailis also a field name in places that aren't logs. Don't add a blanket*.emailredact path that hides useful fields elsewhere; change the two calls.- Expired
sessionsrows are also never swept. Leave them unless it's a one-line addition to the same sweep; say which in the PR. - A sibling issue fixes the cookies page. Both bump a "Last updated" date; whichever lands second has a small merge.
Choices this makes
- IP in the rate-limit warning: default is to drop it (the bucket name is enough to debug), so the page needs no new disclosure.
- Page wording: default is one added phrase in each of the two existing paragraphs, not a new section.
Done when
- No log call under
src/authpasses a full email address. A unit test pins the two log calls' fields. - Housekeeping deletes expired
verification_tokensrows, with a DB test that keeps an unexpired row and deletes an expired one. - The privacy page describes both, with "Last updated" bumped.
pnpm lint && pnpm typecheck && pnpm knip && pnpm test && pnpm test:dbpass.
Found by the pipeline's security scout in sign-in, email and logging (src/auth, src/lib/log.ts, src/jobs, src/app/(legal)), at a9bcff7. Checked by an independent read of the log calls, the redact list, the housekeeping sweeps and the privacy page lines that disagree. https://claude.ai/code/session_01H1WEpHa6h8WwVYLTAKoqhg
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working
Activity