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.
# 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.
# 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.

