Typebot: Account takeover by anonymous brute-force of the magic-link login code

Typebot's e-mail login replaces the default token with a six-digit Math.random() code, and the verify endpoint has no rate limit or lockout at all, so an anonymous attacker can brute-force any account's code and sign in as the victim.

Advisory ID: TP-2026-050
Product: Typebot (open-source builder for chatbots and conversational forms, self-hosted)
Vulnerability type: Account takeover through improperly restricted authentication attempts (CWE-307) with a weak random value (CWE-330)
CVE: CVE-2026-62862
CVSS 3.1: 9.1 (Critical) · CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
Vendor advisory: GHSA-4g76-cwmg-gqgw
Affected versions: Typebot <= 3.17.1
Fixed in: Typebot 3.18.0
Reported: 4 June 2026

Summary

Typebot is a self-hosted builder for chatbots and conversational forms whose default login is a magic link delivered by e-mail. The Nodemailer provider replaces NextAuth's cryptographically strong default token with a six-digit code from Math.random(), a keyspace of only 900,000 values valid for ten minutes. The verify endpoint that checks the submitted code has no rate limit, no lockout and no attempt cap, and a wrong guess does not delete the real token, so it can be guessed an unlimited number of times inside the window. An anonymous attacker who knows only the victim's e-mail address triggers the delivery and brute-forces the code. On success it obtains a valid session and signs in as the victim; for an address that does not yet exist it pre-creates the account.

Root cause

The Nodemailer provider overrides NextAuth's generateVerificationToken with a six-digit Math.random() value (packages/auth/src/lib/providers.ts:43-44) that is also the raw token in the magic link, and the server hashes the submitted code itself with sha256(code+secret), so the attacker submits raw six-digit values without knowing the secret. The verify callback GET /api/auth/callback/nodemailer has no rate limit, no lockout, no attempt cap and no CSRF protection, and a wrong guess removes nothing because useVerificationToken returns null on a P2025 miss (packages/prisma/.../createAuthPrismaAdapter.ts:184-202), so the real token survives the full ten-minute window. The only limiter, oneMinRateLimiter (one call per 60 seconds, nextAuth.ts:97-99), sits on the send path, is keyed through getIp() on the client-supplied X-Forwarded-For header (getIp.ts), and is absent entirely without REDIS_URL. Because coexisting codes do not invalidate one another (each sign-in inserts a new VerificationToken row), rotating X-Forwarded-For values seed N valid codes at once and lower the expected number of guesses to about 900000/N. The magic-link login is the default configuration of the open-source variant as soon as NEXT_PUBLIC_SMTP_FROM is set (providers.ts:25-47); OAuth-only or SSO-only deployments are not affected.

Proof of Concept

# 1) Trigger login-code delivery for the victim (codes do not invalidate each other):
POST /api/auth/signin/nodemailer
X-Forwarded-For: <rotating value>
[email protected]

# 2) Brute-force six-digit codes against the verify callback with no lockout:
GET /api/auth/callback/[email protected]&token=<000000..999999>

# Hit: 302 + Set-Cookie authjs.session-token → victim's session

In the live verification on version 3.17.1, 600 sequential, 1000 parallel and 150 wrong calls from a single IP all stayed at HTTP 302 with no throttling, and the token remained present; rotating X-Forwarded-For values seeded five simultaneously valid codes, while the same IP with no header received only one. A fresh, cookie-less client with the correct code then received Set-Cookie authjs.session-token, and GET /api/auth/session returned the victim's e-mail, with no CSRF token and no victim interaction.

Impact

  • Anonymous takeover of any existing account from knowledge of the victim's e-mail address alone.
  • Full read and write access to the conversation flows, results and stored integrations of the taken-over account.
  • For an address that is not yet registered, the attacker pre-creates the account and controls it when the real user later joins.
  • No victim interaction, no CSRF token and no non-default configuration required once the magic-link login is active.

References

Is Something Like This in Your Software?

Our team found this vulnerability in the course of its work. Have your applications tested by the same specialists, with a penetration test from turingpoint.