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

CVE-2026-54894: Ueberauth Guardian DOS Vulnerability

CVE-2026-54894 is a denial of service vulnerability in Ueberauth Guardian caused by unbounded atom creation from attacker-controlled input. This post covers the technical details, affected versions, impact, and mitigation.

Updated:

CVE-2026-54894 Overview

CVE-2026-54894 is a denial of service vulnerability in Ueberauth Guardian, an authentication library for Elixir applications. The flaw resides in Guardian.Plug.Keys, which passes attacker-influenced binaries to String.to_atom/1 when deriving connection and session namespace keys. Because the BEAM virtual machine never garbage-collects atoms and caps the atom table at roughly 1,048,576 entries, a modest stream of varied inputs permanently exhausts the table and crashes the node. The issue affects guardian versions 0.1.0 through versions before 2.4.1, and is categorized under [CWE-770] Allocation of Resources Without Limits or Throttling.

Critical Impact

Unauthenticated attackers who can influence any request input routed into a Guardian key can permanently consume the BEAM atom table, crashing every application running on the node.

Affected Products

  • Ueberauth Guardian versions 0.1.0 through 2.4.0
  • Elixir/Erlang applications using Guardian.Plug.current_token/2 with caller-supplied keys
  • BEAM nodes hosting Guardian-integrated Phoenix or Plug applications

Discovery Timeline

  • 2026-08-01 - CVE-2026-54894 published to NVD
  • 2026-08-06 - Last updated in NVD database

Technical Details for CVE-2026-54894

Vulnerability Analysis

The vulnerability originates in lib/guardian/plug/keys.ex. The base_key/1 function converts any binary into an atom of the form :"guardian_<input>", and helpers claims_key/1, resource_key/1, and token_key/1 create additional atoms on top of that base. The key_from_other/1 helper likewise converts a regex-captured binary through String.to_atom/1.

Guardian's public specifications advertise String.t() as a valid argument type, meaning callers legitimately pass strings. Higher-level entry points such as Guardian.Plug.current_token(conn, key: key) thread the caller-supplied key directly into these functions without validation or allow-listing.

Root Cause

String.to_atom/1 creates a brand-new atom for every previously unseen binary. Atoms on the BEAM are never garbage-collected, and the atom table is fixed at approximately 1,048,576 entries by default. Any application that routes attacker-influenced data such as a tenant identifier, HTTP header, or arbitrary request parameter into a Guardian key mints one permanent atom per distinct value.

Attack Vector

An attacker sends a stream of requests with varied values in the field that feeds the Guardian key. Each unique value consumes one atom slot permanently. After enough distinct inputs, the atom table fills and the BEAM node crashes, taking down every co-located application. Exploitation does not require authentication when the vulnerable field is exposed to unauthenticated traffic.

text
# Patch excerpt: lib/guardian/plug.ex
      key =
        conn
        |> fetch_key(opts)
-       |> token_key()
+       |> token_key!()

      put_private(conn, key, token)
    end

# Patch excerpt: lib/guardian/plug/verify_cookie.ex
    defp maybe_put_in_session(conn, true, token, opts) do
-     key = conn |> storage_key(opts) |> token_key()
+     key = conn |> storage_key(opts) |> token_key_string()
      put_session(conn, key, token)
    end

Source: Guardian security patch commit. The fix replaces atom-creating helpers with variants that either use existing atoms only (token_key!) or return strings (token_key_string), eliminating unbounded atom creation from user-controlled input.

Detection Methods for CVE-2026-54894

Indicators of Compromise

  • Rapid growth in the BEAM atom table count reported by :erlang.system_info(:atom_count) on Guardian-hosting nodes.
  • Elixir application logs showing sudden node crashes with system_limit errors referencing atoms.
  • High-cardinality values in HTTP headers, tenant identifiers, or query parameters that flow into Guardian key options.

Detection Strategies

  • Instrument runtime telemetry to compare current atom_count against atom_limit and alert when utilization exceeds a defined threshold.
  • Audit application source code for calls to Guardian.Plug.current_token/2, Guardian.Plug.put_current_token/3, and related functions where the :key option derives from request data.
  • Review reverse proxy and web application firewall logs for repeated requests with varied, high-entropy values in fields tied to Guardian keys.

Monitoring Recommendations

  • Ship BEAM VM metrics including atom_count, atom_limit, and process counts to a centralized observability platform.
  • Track dependency versions across the Elixir application fleet to identify hosts still running guardian below 2.4.1.
  • Alert on abnormal spikes in unauthenticated traffic patterns that could indicate atom-exhaustion probing.

How to Mitigate CVE-2026-54894

Immediate Actions Required

  • Upgrade guardian to version 2.4.1 or later in mix.exs and redeploy affected applications.
  • Audit all call sites that pass a :key option to Guardian plugs and confirm the value does not derive from untrusted input.
  • Restart BEAM nodes after upgrade to reset any atom-table pressure accumulated during exposure.

Patch Information

The upstream fix is included in Guardian 2.4.1 and documented in the GitHub Security Advisory GHSA-xqch-c77q-rgh5. The corresponding source change is available in the Guardian security patch commit. Additional metadata is published in the CNA advisory for CVE-2026-54894 and the OSV entry EEF-CVE-2026-54894.

Workarounds

  • Restrict Guardian :key values to a static allow-list of known atoms defined at compile time rather than user-supplied strings.
  • Wrap any dynamic key derivation with String.to_existing_atom/1 guarded by a try/rescue to prevent creation of new atoms.
  • Deploy input validation at the ingress layer to reject high-cardinality values in headers or parameters that flow into Guardian keys.
bash
# Update dependency in mix.exs and refresh the lock file
# {:guardian, "~> 2.4.1"}
mix deps.update guardian
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.

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.