Vulnerability DatabaseGHSA-3xj6-982x-2r3g

GHSA-3xj6-982x-2r3g: 
JavaScript vulnerability analysis and mitigation

Summary

Logto's one-time token verification contains a TOCTOU race condition. The verifyOneTimeToken() function reads a token's status as Active, validates it, then issues an UPDATE query that has no WHERE status = Active predicate. Under PostgreSQL Read Committed isolation, two concurrent transactions can both read Active, both pass validation, and both update the row to Consumed - each returning success to the caller.

Impact

A one-time password-reset token or magic-link token that should be single-use can be consumed by two concurrent flows:

  • Password reset replay: An attacker with the token can race the verification to establish two independent password-reset sessions and call resetPassword() on each to set a password of their choice (account takeover).
  • Magic-link dual sign-in: Two tabs loading the same sign-in token URL can both complete sign-in, creating two authenticated sessions from one token.

Root Cause

packages/core/src/queries/one-time-tokens.ts has an updateOneTimeTokenStatus function that issues: UPDATE one_time_tokens SET status = Consumed WHERE token = $token RETURNING * There is no AND status = Active predicate. Both concurrent writers succeed. packages/core/src/libraries/one-time-token.ts#verifyOneTimeToken() performs a read-then-write: checkOneTimeToken() reads and validates the token is Active, then updateOneTimeTokenStatus() updates to Consumed without checking current status. Under PostgreSQL Read Committed:

  • T1 reads status=Active (passes check)
  • T2 reads status=Active (passes check, T1 has not committed yet)
  • T1 UPDATE to Consumed, commits
  • T2 UPDATE to Consumed (finds row by token, no status predicate - succeeds)

Affected Routes

  • Management API: POST /api/one-time-tokens/verify
  • Experience API: POST /experience/verification/one-time-token/verify
  • Forgot-password flow: identifyForgotPasswordWithOneTimeToken()

Proof

PostgreSQL-backed concurrency test: 30/30 race iterations both transactions successfully verified the same Active token (100% reproduction).

Remediation

Add AND status = Active to the UPDATE WHERE clause: UPDATE one_time_tokens SET status = Consumed WHERE token = $token AND status = Active RETURNING *

Credit

Anonymous researcher


Source: NVD

Related JavaScript vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

GHSA-cr4j-qhrf-249wHIGH7.5
  • JavaScript logoJavaScript
  • @logto/tunnel
NoYesNov 09, 2026
GHSA-2pq4-jqvf-f7qjMEDIUM6.5
  • JavaScript logoJavaScript
  • @logto/core
NoYesNov 09, 2026
GHSA-c5hj-jm58-pxh9MEDIUM6.5
  • JavaScript logoJavaScript
  • @logto/core
NoYesNov 09, 2026
GHSA-3xj6-982x-2r3gMEDIUM6.5
  • JavaScript logoJavaScript
  • @logto/core
NoYesNov 09, 2026
GHSA-ffj9-42qx-f38hMEDIUM6.3
  • JavaScript logoJavaScript
  • @angular/upgrade
NoYesNov 09, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Additional Wiz resources

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management