Skip to content

OAuth state and PKCE code verifier are generated with Math.random()

Moderate
yusukebe published GHSA-6833-cxmv-fqjf Aug 4, 2026

Package

npm @hono/oauth-providers (npm)

Affected versions

<= 0.8.6

Patched versions

0.8.7

Description

Summary

Every provider generated the OAuth state parameter with Math.random(), and the X (Twitter) provider generated its PKCE code_verifier the same way. Math.random() is not a cryptographically secure pseudorandom number generator, so neither value is unpredictable.

Details

The state parameter is the anti-CSRF token of the authorization flow and must be unguessable (RFC 6749 Section 10.12), and RFC 7636 Section 7.1 requires the PKCE code_verifier to come from a cryptographically secure generator. Both were derived from Math.random(), which V8 implements as xorshift128+: its internal state is recoverable from a small number of observed outputs, after which every subsequent value follows deterministically. The generator is a single stream shared across requests on an instance, and each authorization request emits a fresh state in a redirect URL that whoever initiated it can read.

This issue affects all providers. Applications that supply their own state through the state option, available on googleAuth, msentraAuth and twitchAuth, do not reach the affected path for that value.

Impact

An attacker able to sample the generator's output may predict state values issued to other requests on the same instance, defeating the protection the parameter provides. This may lead to:

  • Login CSRF, where the victim continues inside the attacker's account
  • Forced account linking, where the attacker's identity is attached to the victim's account

Recovering the generator state and aligning it with a concurrent request is intricate, which limits practical exploitation. On the X provider the same weakness applies to the code_verifier, which is what otherwise binds a callback to the browser that started the flow.

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
High
Privileges required
None
User interaction
Required
Scope
Unchanged
Confidentiality
Low
Integrity
Low
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:N

CVE ID

No known CVE

Weaknesses

Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)

The product uses a Pseudo-Random Number Generator (PRNG) in a security context, but the PRNG's algorithm is not cryptographically strong. Learn more on MITRE.

Credits