Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-65633

CVE-2026-65633: AshAuthentication JWT Auth Bypass Vulnerability

CVE-2026-65633 is an authentication bypass flaw in team-alembic AshAuthentication that allows purpose-limited JWTs to be replayed as full bearer API credentials. This post explains its impact, affected versions, and mitigation steps.

Published:

CVE-2026-65633 Overview

CVE-2026-65633 is an improper authentication vulnerability [CWE-287] in the team-alembic ash_authentication library for Elixir. The bearer-token helper AshAuthentication.Plug.Helpers.retrieve_from_bearer/3 verifies JWT signatures and rejects tokens containing an act claim, but does not check that the token's purpose claim equals user at the bearer boundary. Purpose-limited JWTs, such as the sign_in token issued by WebAuthn and the Password strategy, can be replayed directly in an Authorization: Bearer header and resolve to a full current_user assignment. The flaw affects ash_authentication from 3.10.5 before 4.14.2 and from 5.0.0-rc.0 before 5.0.0-rc.13.

Critical Impact

An attacker who obtains a not-yet-exchanged sign_in token can authenticate as the target subject, bypassing the library's one-time-use and revocation contract.

Affected Products

  • team-alembic ash_authentication 3.10.5 through versions before 4.14.2
  • team-alembic ash_authentication 5.0.0-rc.0 through versions before 5.0.0-rc.13
  • Applications using WebAuthn or the Password strategy with sign_in_tokens_enabled?: true and require_token_presence_for_authentication?: false

Discovery Timeline

  • 2026-08-25 - CVE-2026-65633 published to NVD
  • 2026-08-25 - Last updated in NVD database

Technical Details for CVE-2026-65633

Vulnerability Analysis

The ash_authentication library issues purpose-scoped JWTs for narrow flows. The sign_in token, emitted by WebAuthn and the Password strategy, is intended to be exchanged exactly once through a preparation that validates the purpose claim and revokes the token. The stateless bearer path never enforces this contract.

retrieve_from_bearer/3 calls Jwt.verify/3 and rejects tokens carrying an act claim, but performs no purpose check. When the resource is configured with require_token_presence_for_authentication?: false (the DSL default), the follow-on validate_token/3 returns {:ok, nil} without consulting the stored token record. No downstream code enforces purpose == "user", so a sign_in token is accepted as a general-purpose bearer credential.

Root Cause

The root cause is missing purpose-scope validation at the bearer authentication boundary. The library treats a valid JWT signature and absence of the act claim as sufficient for bearer authentication, conflating narrow, purpose-limited tokens with full user-session credentials. The session-based path authenticate_resource_from_session/4 and configurations with require_token_presence_for_authentication?: true correctly enforce the purpose claim against the token resource and are not affected.

Attack Vector

An attacker must obtain a still-valid, not-yet-exchanged sign_in token for the target subject. Realistic exposure paths include referrer or log leakage of magic-link URLs, interception of magic-link delivery channels, or a partially compromised intermediary. The attacker submits the captured token as Authorization: Bearer <token> to any route wired to retrieve_from_bearer/3, and the request resolves as the target user.

text
     |> Enum.reduce(conn, fn token, conn ->
       with {:ok, %{"sub" => subject, "jti" => jti} = claims, resource}
            when not is_map_key(claims, "act") <- Jwt.verify(token, otp_app, opts),
+           true <- usable_as_bearer_token?(claims),
            {:ok, token_record} <-
              validate_token(resource, jti, opts),
            {:ok, user} <-

Source: GitHub Commit 124eddd1. The patch inserts a usable_as_bearer_token?/1 guard that rejects tokens whose purpose claim is not user before validate_token/3 is called.

Detection Methods for CVE-2026-65633

Indicators of Compromise

  • Successful authenticated requests where the presented JWT carries a purpose claim other than user (for example sign_in).
  • Repeated presentation of the same jti value across multiple bearer requests, indicating replay of a one-time token.
  • Bearer authentications for a subject that lack a corresponding session-establishment event or token-exchange record.

Detection Strategies

  • Decode inbound JWTs at the reverse proxy or application logger and alert on any purpose value other than user reaching bearer-protected routes.
  • Correlate jti values in application logs against the stored token resource to detect tokens presented after they should have been revoked.
  • Audit application routing to enumerate every plug that invokes retrieve_from_bearer/3 and confirm the associated resource configuration.

Monitoring Recommendations

  • Log full JWT claim sets (excluding signatures) for bearer authentications during the remediation window.
  • Alert on magic-link URLs appearing in HTTP referrer headers, web server access logs, or outbound proxy logs.
  • Monitor for unexpected access from IP addresses or user agents that do not match the target user's normal session pattern.

How to Mitigate CVE-2026-65633

Immediate Actions Required

  • Upgrade ash_authentication to 4.14.2 or 5.0.0-rc.13 or later.
  • Set require_token_presence_for_authentication?: true on any resource exposed through retrieve_from_bearer/3 until the upgrade is complete.
  • Revoke any outstanding sign_in tokens by clearing the token resource, forcing re-authentication.
  • Rotate JWT signing secrets if sign_in tokens may have been exposed through logs, referrers, or intercepted delivery channels.

Patch Information

The fix is delivered in ash_authentication versions 4.14.2 and 5.0.0-rc.13. The commits 124eddd1 and 8cf8b2d4 add a usable_as_bearer_token?/1 guard in lib/ash_authentication/plug/helpers.ex that rejects any JWT whose purpose claim is not user before the bearer path returns a current_user. See the GitHub Security Advisory GHSA-6vcj-3h59-rrc3 and the CNA advisory for the full disclosure.

Workarounds

  • Set require_token_presence_for_authentication?: true on affected resources so the token resource is consulted and purpose == "user" is enforced.
  • Prefer the session-based path authenticate_resource_from_session/4, which is not affected.
  • Disable sign_in_tokens_enabled? on the Password strategy where it is not required, and restrict WebAuthn flows to trusted transport channels.
bash
# Configuration example - enforce token presence on affected resources
# In your Ash resource module:
#
#   authentication do
#     tokens do
#       enabled? true
#       require_token_presence_for_authentication? true
#     end
#   end
#
# Then upgrade the dependency in mix.exs:
#   {:ash_authentication, "~> 4.14.2"}
mix deps.update ash_authentication
mix compile --force

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.