Skip to content

Back to the catalog

Insecure cryptographic defaults in oidcProvider: alg=none advertised and plain PKCE accepted by default
github.comadvisory

Insecure cryptographic defaults in oidcProvider: alg=none advertised and plain PKCE accepted by default

GHSA advisory for better-auth (< 1.6.11) documenting that the deprecated oidcProvider() and mcp() plugins publish "none" as a supported ID-token signing algorithm in their OIDC discovery document and default allowPlainCodeChallengeMethod to true, silently rewriting missing code_challenge_method to "plain" — both violating OAuth 2.1/RFC 9700. The fix removes "none" from the metadata, defaults plain PKCE to disabled, and rejects requests missing code_challenge_method instead of downgrading them; @better-auth/oauth-provider was never affected.

TL;DR better-auth's oidcProvider/mcp plugins advertised alg=none and accepted plain PKCE by default before 1.6.11 — patched to require S256 and drop none from discovery metadata.
Document

What it is

GHSA-9h47-pqcx-hjr4 covers two insecure cryptographic defaults in better-auth's legacy oidcProvider() plugin (and the mcp() plugin, which delegates to it and inherits both defaults). The OIDC discovery document advertises "none" as a supported id_token_signing_alg, and PKCE plain is accepted by default. Fixed in better-auth@1.6.11.

How it works

Two distinct defects:

  • alg=none advertised. The metadata builders unconditionally inject "none" into id_token_signing_alg_values_supported (and, for mcp, into resource_signing_alg_values_supported on the OAuth protected-resource metadata). A relying party whose JWT library negotiates the algorithm from discovery without pinning can be steered into accepting unsigned tokens.
  • plain PKCE accepted and silently defaulted. The authorize handler accepts code_challenge_method=plain, and a missing code_challenge_method is rewritten to "plain" before the allowlist check runs — so even a client that strips the parameter lands in the plain path. This directly contradicts discovery, which advertises code_challenge_methods_supported: ["S256"]. RFC 9700 §2.1.1 (OAuth 2.1) forbids plain.

Preconditions / Affected

All must be true: better-auth below 1.6.11, and oidcProvider() or mcp() enabled. Then:

  • alg-none impact requires a relying party that negotiates the signing alg from discovery without pinning.
  • PKCE impact requires the authorization URL to leak to any party other than the user agent and the OP (Referer headers, browser history, screen capture, proxy logs), enabling authorization-code interception.

Users of @better-auth/oauth-provider (the canonical replacement) who never enabled the legacy plugins are not affected — its metadata type union structurally excludes none, and its authorize schema is z.literal("S256").optional(), rejecting plain at parse time.

What to do

Upgrade to better-auth@1.6.11 or later, and migrate to @better-auth/oauth-provider when feasible. The patch drops none from both alg lists, defaults allowPlainCodeChallengeMethod to false, and rejects a code_challenge sent without an accompanying code_challenge_method instead of rewriting it to plain.

If you cannot upgrade:

  • Disable plain PKCE explicitly:
oidcProvider({ allowPlainCodeChallengeMethod: false })

(equivalent on mcp). Note: this closes runtime acceptance of plain but the silent downgrade of a missing method still rewrites it.

  • Override the metadata to drop none:
oidcProvider({ metadata: { id_token_signing_alg_values_supported: ["RS256"] } })

For mcp, set the same on options.oidcConfig.metadata. Verify by curling the .well-known endpoint.

Caveats

The workaround for plain PKCE is partial: with allowPlainCodeChallengeMethod: false on an unpatched version, a request that omits code_challenge_method is still silently treated as plain — only the patch (1.6.11) rejects that case. Integrators needing plain for legacy clients can re-enable it post-patch with allowPlainCodeChallengeMethod: true, which restores the silent-downgrade behavior for everyone using that instance.

Organisations named here

  • PKCE
  • RFC 9700

Technologies named here

  • better-auth
  • oidcProvider plugin
  • mcp plugin
  • @better-auth/oauth-provider
  • OIDC
  • OAuth
  • OAuth 2.1

Techniques named here

  • Unsigned tokens via alg=none
  • Plain PKCE downgrade