CVE-2026-54904: Concurrent Ruby `AtomicReference#update` Livelocks When The Stored Vulnerability
HIGHCVE-2026-54904 is a HIGH (CVSS 7.5) `atomicreference#update` livelocks when the stored vulnerability (CWE-835: Loop with Unreachable Exit Condition ('Infinite Loop')) affecting Concurrent Ruby libraries in the RubyGems ecosystem. The issue involves `atomicreference#update` livelocks when the stored value is `float::nan`. Remediation is available by upgrading affected packages to version 1.3.7.
CVE-2026-54904 at a Glance
Security Impact
CVSS: 7.5
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H).
How to Fix CVE-2026-54904
To remediate this vulnerability, upgrade all affected Concurrent Ruby dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
Upgrade concurrent-ruby to 1.3.7
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
inspect dependencies for concurrent-ruby
How to Check if You Are Affected
To determine whether your application is affected by CVE-2026-54904, inspect your project dependencies for Concurrent Ruby:
inspect dependencies for concurrent-ruby
Analyze the terminal output to locate any version of Concurrent Ruby in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.3.7), your application is affected.
Note: Verify declared build manifests and deployed runtime container environments.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-835: Loop with Unreachable Exit Condition ('Infinite Loop'), where the product contains an iteration or loop with an exit condition that cannot be reached, i.e., an infinite loop. In Concurrent Ruby, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-54904 Affected Concurrent Ruby Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
concurrent-ruby
|
RubyGems |
< 1.3.7
|
1.3.7
|
References
Frequently Asked Questions
What is CVE-2026-54904?
Which Concurrent Ruby versions are affected?
What version fixes CVE-2026-54904?
Is concurrent-ruby affected?
What is the CVSS score of CVE-2026-54904?
What CWE is associated with CVE-2026-54904?
How can I check RubyGems dependencies for CVE-2026-54904?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-h8w8-99g7-qmvj",
"modified" : "2026-08-05T17:36:06Z",
"published" : "2026-06-19T20:47:35Z",
"aliases" : [ "CVE-2026-54904" ],
"summary" : "Concurrent Ruby : `AtomicReference#update` livelocks when the stored value is `Float::NAN`",
"details" : "### Summary\n`Concurrent::AtomicReference#update` can enter a permanent busy retry loop when the current value is `Float::NAN`.\n\nThe issue is caused by the interaction between:\n- `AtomicReference#update`, which retries until `compare_and_set(old_value, new_value)` succeeds.\n- Numeric `compare_and_set`, which checks `old == old_value` before attempting the underlying atomic swap.\n- Ruby NaN semantics, where `Float::NAN == Float::NAN` is always `false`.\n\nAs a result, once an `AtomicReference` contains `Float::NAN`, calling `#update` repeatedly evaluates the caller's block and never returns. In services that store externally derived numeric values in an `AtomicReference`, this can cause CPU exhaustion or permanent request/job hangs.\n\n### Version\nSoftware: concurrent-ruby\nVersion: 1.3.6\nCommit: 7a1b78941c081106c20a9ca0144ac73a48d254ab\n### Details\n\n`AtomicReference#update` retries until `compare_and_set` returns true:\n\n```ruby\ndef update\n true until compare_and_set(old_value = get, new_value = yield(old_value))\n new_value\nend\n```\n\nFor numeric expected values, `compare_and_set` uses numeric equality before attempting the underlying atomic compare-and-set:\n\n```ruby\ndef compare_and_set(old_value, new_value)\n if old_value.kind_of? Numeric\n while true\n old = get\n\n return false unless old.kind_of? Numeric\n return false unless old == old_value\n\n result = _compare_and_set(old, new_value)\n return result if result\n end\n else\n _compare_and_set(old_value, new_value)\n end\nend\n```\n\nWhen the stored value is `Float::NAN`, `old_value = get` returns NaN. The later comparison `old == old_value` is false because NaN is not equal to itself. `compare_and_set` therefore returns false every time. `AtomicReference#update` treats that as a failed concurrent update and retries forever.\n\nThis is reachable through the public `Concurrent::AtomicReference` API and does not require native extensions or undefined behavior.\n\n### PoC\n\n```ruby\n#!/usr/bin/env ruby\n# frozen_string_literal: true\n\nrequire 'concurrent/atomic/atomic_reference'\nrequire 'concurrent/version'\n\nputs \"ruby=#{RUBY_DESCRIPTION}\"\nputs \"concurrent_ruby_version=#{Concurrent::VERSION}\"\nputs \"poc=AtomicReference#update livelock when current value is Float::NAN\"\n\nref = Concurrent::AtomicReference.new(Float::NAN)\nattempts = 0\nfinished = false\n\nworker = Thread.new do\n ref.update do |_old_value|\n attempts += 1\n 0.0\n end\n finished = true\nend\n\nsleep 0.25\n\nputs \"nan_update_attempts_after_250ms=#{attempts}\"\nputs \"nan_update_finished=#{finished}\"\nputs \"nan_update_worker_alive=#{worker.alive?}\"\n\nif worker.alive? && !finished && attempts > 1000\n puts 'result=REPRODUCED busy retry loop; update did not complete'\nelse\n puts 'result=NOT_REPRODUCED'\nend\n\nworker.kill\nworker.join\n\ncontrol = Concurrent::AtomicReference.new(1.0)\ncontrol_attempts = 0\ncontrol_result = control.update do |old_value|\n control_attempts += 1\n old_value + 1.0\nend\n\nputs \"control_update_result=#{control_result.inspect}\"\nputs \"control_update_attempts=#{control_attempts}\"\nputs \"control_update_final_value=#{control.value.inspect}\"\n```\n### Log evidence\n```text\nruby=ruby 2.6.10p210 (2022-04-12 revision 67958) [universal.arm64e-darwin25]\nconcurrent_ruby_version=1.3.6\npoc=AtomicReference#update livelock when current value is Float::NAN\nnan_update_attempts_after_250ms=1926016\nnan_update_finished=false\nnan_update_worker_alive=true\nresult=REPRODUCED busy retry loop; update did not complete\ncontrol_update_result=2.0\ncontrol_update_attempts=1\ncontrol_update_final_value=2.0\n```\n\n### Impact\nThis is an application-level denial of service issue. If an application stores externally derived numeric data in a `Concurrent::AtomicReference`, an attacker or faulty upstream data source may be able to cause the stored value to become `Float::NAN`. Any later call to `AtomicReference#update` on that reference will spin indefinitely, repeatedly executing the update block and consuming CPU.\n\n### Credit\nPranjali Thakur - depthfirst ([depthfirst.com](<http://depthfirst.com>))",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
}, {
"type" : "CVSS_V4",
"score" : "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "RubyGems",
"name" : "concurrent-ruby"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "1.3.7"
} ]
} ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/ruby-concurrency/concurrent-ruby/security/advisories/GHSA-h8w8-99g7-qmvj"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-54904"
}, {
"type" : "WEB",
"url" : "https://github.com/ruby-concurrency/concurrent-ruby/commit/6e37e0644b83b182971dc540d2e4bee38df61386"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/ruby-concurrency/concurrent-ruby"
}, {
"type" : "WEB",
"url" : "https://github.com/ruby-concurrency/concurrent-ruby/releases/tag/v1.3.7"
}, {
"type" : "WEB",
"url" : "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/concurrent-ruby/CVE-2026-54904.yml"
}, {
"type" : "WEB",
"url" : "https://www.cve.org/CVERecord/SearchResults?query=CVE-2026-54904"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-835" ],
"severity" : "HIGH",
"github_reviewed" : true,
"github_reviewed_at" : "2026-06-19T20:47:35Z",
"nvd_published_at" : "2026-06-24T17:17:29Z"
}
}