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

CVE-2026-82758: Ash OAuth2 Server Auth Bypass Vulnerability

CVE-2026-82758 is an authentication bypass flaw in ash_authentication_oauth2_server that allows unauthenticated attackers to register OAuth clients. This post covers technical details, affected versions, and mitigation steps.

Published:

CVE-2026-82758 Overview

CVE-2026-82758 is an improper authentication vulnerability [CWE-287] in the ash-project/ash_authentication_oauth2_server Elixir library. The flaw allows an unauthenticated attacker to register OAuth clients through the Dynamic Client Registration (DCR) endpoint even when registration is gated by an initial_access_token. The resolve_secret/3 function in AshAuthentication.Oauth2Server fails open when a configured secret provider returns nil, false, or an empty string. That behavior converts a closed registration configuration into an open one and also affects other resolved secrets such as signing_secret. The issue impacts versions from 0.1.0 before 0.3.1.

Critical Impact

Attackers can register arbitrary OAuth clients against a server operator's authorization service without presenting a valid bearer token, defeating the DCR access-token gate.

Affected Products

  • ash_authentication_oauth2_server versions 0.1.0 through 0.3.0
  • Elixir applications using the Ash Framework OAuth2 server with a configured initial_access_token provider
  • Deployments relying on resolve_secret/3 for any secret value, including signing_secret

Discovery Timeline

  • 2026-09-07 - CVE-2026-82758 published to NVD
  • 2026-09-08 - Last updated in NVD database

Technical Details for CVE-2026-82758

Vulnerability Analysis

The vulnerability resides in resolve_secret/3 within AshAuthentication.Oauth2Server, reached through __resolve_secret__!. The function accepts secret providers configured as either a {module, function, args} tuple or a 2-arity function. It matched on {:ok, value} and :error return shapes but treated every other return as a valid secret by wrapping it in {:ok, value}.

When a provider returned nil, false, or "", the resolver produced {:ok, nil}, {:ok, false}, or {:ok, ""} instead of failing. POST /oauth/register then compared the client-supplied bearer token against this empty value. The comparison succeeded when no token was supplied, opening registration to unauthenticated callers.

Root Cause

The secret resolver did not enforce a type or non-empty invariant on provider return values. Any truthy or falsy non-tuple result was accepted as a legitimate secret, violating the fail-closed principle expected of authentication gates.

Attack Vector

An unauthenticated remote attacker sends a POST /oauth/register request with no Authorization header. If the deployment's initial_access_token provider resolves to an empty value under any runtime condition (missing environment variable, unloaded config), the bearer-token comparison passes and the attacker registers an arbitrary OAuth client.

elixir
// Patch excerpt - lib/ash_authentication/oauth2_server.ex
  defp resolve_secret({mod, fun, args}, module, path, _context)
       when is_atom(mod) and is_atom(fun) and is_list(args) do
-   case apply(mod, fun, [path, module | args]) do
-     {:ok, value} -> {:ok, value}
-     :error -> :error
-     other -> {:ok, other}
-   end
+   mod |> apply(fun, [path, module | args]) |> normalize_resolved_secret()
  end

  defp resolve_secret(fun, module, path, _context) when is_function(fun, 2) do
-   case fun.(path, module) do
-     {:ok, value} -> {:ok, value}
-     :error -> :error
-     other -> {:ok, other}
-   end
+   fun.(path, module) |> normalize_resolved_secret()
  end

+ # A resolved secret must be a non-empty binary. Treat nil, false, "",
+ # {:error, _}, {:ok, nil} and any non-binary as a resolution failure.
+ defp normalize_resolved_secret({:ok, value}) when is_binary(value) and value != "",
+   do: {:ok, value}

Source: GitHub Commit 30a8710

Detection Methods for CVE-2026-82758

Indicators of Compromise

  • Successful POST /oauth/register requests originating from unexpected IPs without an Authorization: Bearer header
  • Newly registered OAuth clients that do not correspond to any provisioning workflow or ticket
  • Application logs showing initial_access_token resolving to nil, false, or empty string values

Detection Strategies

  • Audit the OAuth client registration table for entries created outside of expected change windows or without an associated operator identity
  • Instrument the secret provider callback to log and alert on any non-binary or empty return value
  • Correlate DCR endpoint access logs with authenticated administrative sessions to identify anomalous unauthenticated registrations

Monitoring Recommendations

  • Enable structured request logging on /oauth/register including presented bearer token presence and client metadata
  • Alert on registration bursts or registrations from IP ranges outside internal automation
  • Monitor Elixir application telemetry for AshAuthentication.Oauth2Server secret-resolution failures after upgrade

How to Mitigate CVE-2026-82758

Immediate Actions Required

  • Upgrade ash_authentication_oauth2_server to version 0.3.1 or later
  • Review all OAuth clients registered since the vulnerable version was deployed and revoke any that are not attributable to legitimate operators
  • Rotate signing_secret and any other secrets resolved through the affected provider path, since they may have silently resolved to empty values

Patch Information

The fix is delivered in commit 30a8710 and released in version 0.3.1. The patch introduces normalize_resolved_secret/1, which requires a non-empty binary and raises rather than silently accepting nil, false, "", or non-binary values. See the GitHub Security Advisory GHSA-fxc6-vp68-87pw and CNA CVE-2026-82758 Details for authoritative references.

Workarounds

  • Disable Dynamic Client Registration entirely if an upgrade cannot be applied immediately
  • Add a reverse-proxy rule requiring a non-empty Authorization: Bearer header on /oauth/register
  • Wrap the initial_access_token provider so it raises when the underlying source returns nil, false, or an empty string
bash
# Update mix.exs to require the patched version
# {:ash_authentication_oauth2_server, "~> 0.3.1"}
mix deps.update ash_authentication_oauth2_server
mix deps.get
mix compile --force

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

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.