Skip to content

signup: /api/users/bootstrap trusts client-supplied body.email instead of the verified token email #22

Description

@dylanroscover

Found during the cross-model pre-deploy review of #20 (Codex, signup-security dimension).

requireSessionOrIdToken() returns only the uid; the route then validates and persists the client-supplied body.email (web/app/api/users/bootstrap/route.ts — email validation + isDisposableEmailDomain(body.email) + bootstrapUser({ email: body.email })). Because the server write uses the Admin SDK, it bypasses the email == request.auth.token.email pin in firestore.rules.

Impact (medium, pre-existing — not introduced by #20, but the new disposable control inherits it):

  • A bot can sign up via Firebase with a disposable address (e.g. bot@mailinator.com), then POST bootstrap with body.email = clean@gmail.com → passes the disposable filter and stores a falsified email.
  • The stored users/{uid}.email is attacker-controlled (admin user-list shows a spoofable address; any logic keyed on it reads an unverified value). No priv-esc (uid/role/sites are pinned).

Fix: use the verified email from the decoded ID token (or getAdminAuth().getUser(uid).email) for both the disposable check and the persisted value; ignore body.email (or reject when it doesn't match the verified email).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions