Skip to main content

concurrent-ruby CVE-2026-54904

| EUVDEUVD-2026-38810 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
View

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain

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

Vulnerability Assessment

Weakness
CWE
ASVS 5.0
V15 - Secure Coding and Architecture Loop termination conditions
MITRE ATT&CK

1 technique across 1 tactic: Impact

The technique list with ATT&CK links and the kill-chain view is part of the Basic plan and up.

Exploitation Conditions

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. This matches the CVSS AT:P (Attack Requirement: Present) metric: the flaw is network-reachable and needs no authentication or user interaction (PR:N/UI:N), but it is NOT triggerable against an arbitrary default deployment - it only manifests where this specific AtomicReference-storing-numeric-then-update code pattern exists and exposes the stored value to external influence. The main limiting factor is therefore this application coding pattern; applications that never store untrusted Floats in AtomicReference, or that validate with .finite? before storing, are not exploitable regardless of concurrent-ruby version.

Impact

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. The AT:P metric is the key qualifier: exploitation is not unconditional but depends on the application actually storing externally-influenced numeric data in an AtomicReference and later calling #update on it - a real but non-universal coding pattern. No EPSS score, KEV listing, or SSVC decision was supplied; absence of these signals means widespread automated exploitation is not evidenced. A working PoC is published in the advisory (publicly available exploit code exists), which raises practical risk above a theoretical-only finding, but impact is confined to denial of service - there is no confidentiality or integrity exposure (VC:N/VI:N). Net assessment: a genuine but conditional availability risk whose real-world severity is governed almost entirely by whether a given application exposes the vulnerable AtomicReference/update pattern to attacker- or upstream-controlled numeric input; for applications that do not, practical risk is low despite the High CVSS.

Exploit ScenarioDerived

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. the result of 0.0/0.0 or a malformed numeric field), and the next time the service calls ref.update to adjust that value, the worker thread enters a permanent busy retry loop. The published PoC confirms this spins millions of times per second and never returns, pinning a CPU core and hanging the request or job.

This Week Schedule remediation this week. Why: HIGH severity (CVSS 7.0-8.9).
Patch available 0.3% exploitation probability (EPSS)

Get an e-mail when this CVE is exploited, patched or re-scored. Free account.

Alert me

AnalysisAIv3 – Jun 24, 2026

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). Publicly available exploit code exists; there is no public exploit identified as being used in active attacks, and the issue is not listed in CISA KEV.

Earlier versions of this analysis (2)
v2 Jun 24, 2026 - 17:32 cvss changed CVSS 8.2

Denial of service in the concurrent-ruby gem (versions through 1.3.6) lets a poisoned numeric value permanently hang any thread that calls Concurrent::AtomicReference#update. Because Ruby evaluates Float::NAN == Float::NAN as false, the numeric compare_and_set path never confirms the swap once a reference holds NaN, so #update spins in an unbounded busy-retry loop, repeatedly executing the caller's block and burning CPU. A working proof-of-concept is published in the GitHub Security Advisory (GHSA-h8w8-99g7-qmvj); there is no public exploit identified as actively used, and the issue is not in CISA KEV. The vendor fixed it in 1.3.7.

v1 Jun 19, 2026 - 21:37

Denial of service in the concurrent-ruby gem (versions prior to 1.3.7) allows attackers to trigger an infinite busy-retry loop in Concurrent::AtomicReference#update when the stored value becomes Float::NAN. Because Ruby NaN semantics make Float::NAN == Float::NAN always false, compare_and_set never succeeds, causing CPU exhaustion and indefinite hangs. No public exploit identified at time of analysis beyond the reporter's reproducer, but the PoC is published in the GHSA advisory.

RemediationAI

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). Where immediate upgrade is not possible, apply application-level compensating controls: validate and reject non-finite floats before storing externally-derived numeric data in an AtomicReference (e.g. guard with value.finite? and substitute a safe default or raise on NaN/Infinity), which closes the input vector at the cost of added validation logic on numeric ingestion paths; alternatively replace the vulnerable AtomicReference#update calls with a guarded read-modify-write that special-cases NaN, or avoid storing raw Float values from untrusted upstream sources in AtomicReference entirely. Each workaround requires code changes and careful coverage of all numeric ingestion points, so upgrading to 1.3.7 remains preferable.

Affected VersionsENISA

concurrent-ruby < 1.3.7

Affected Packages

rubygems concurrent-ruby fix: 1.3.7

Source: OSV (Open Source Vulnerabilities)

Affects your stack

Affects 1 package in rubygems

Checking this CVE against your own stacks and servers is part of the Basic plan and up.

Technical ContextAI · show details

concurrent-ruby is a widely used Ruby gem providing thread-safe concurrency primitives, including Concurrent::AtomicReference, which offers atomic compare-and-set semantics. The root cause is CWE-835 (Loop with Unreachable Exit Condition, i.e. an infinite loop / livelock). AtomicReference#update is implemented as 'true until compare_and_set(old_value = get, new_value = yield(old_value))'. For Numeric expected values, compare_and_set guards the underlying atomic swap with a numeric equality check 'old == old_value' before calling _compare_and_set. IEEE-754 / Ruby NaN semantics dictate that NaN is never equal to itself, so when the stored value is Float::NAN the equality guard is permanently false, compare_and_set always returns false, and update interprets this as an unending stream of failed concurrent updates and retries forever. The affected package is identified by CPE pkg:rubygems/concurrent-ruby, and the flaw is reachable purely through the public API without native extensions or undefined behavior.

Know when the next one hits your stack

  • Watch products and get an email when something new is published
  • Check this CVE against your own stack and servers
  • Exploit and PoC references, threat intelligence from 22 sources

No credit card · 7-day full trial

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

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

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

Attack Vector
Network
Attack Complexity
Low
Attack Requirements
Present
Privileges Required
None
User Interaction
None
Vulnerable system: Confidentiality
None
Vulnerable system: Integrity
None
Vulnerable system: Availability
High
Subsequent system: Confidentiality
None
Subsequent system: Integrity
None
Subsequent system: Availability
None

Lifecycle Timeline

3
Analysis Updated
Jun 24, 2026 - 17:32 vuln.today
v3 - CVSS changed
Analysis Updated
Jun 24, 2026 - 17:32 vuln.today
v2 - CVSS changed
CVSS changed
Jun 24, 2026 - 17:22 NVD
8.2 (HIGH)

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>))

Executive ViewAI

Why It Matters

The concurrent-ruby gem, a common dependency in Ruby applications, contains a vulnerability that attackers can exploit with publicly available code to disable affected services through resource exhaustion. Organizations running concurrent-ruby versions 1.3.6 or earlier face potential service outages impacting customer availability and operations. A vendor patch is available and should be deployed immediately to restore normal operational resilience.

Business Impact: High
Compensating Controls

Apply vendor patch.

Threat Intelligence Overview

EPSS Score
0.3%
Top 84% exploitable
Prevalence
High
core concurrency gem, transitive dependency in very many Ruby/Rails apps
Threat Intel
1
1 source
Social Media
1
Sightings
Data Quality
7 sources
Confidence: High

How this decision was reached

The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.

SignalValue
Severity HIGH
CISA KEV No
Public POC No
EPSS 0.3%
Patch available Yes
Active threat No
Deciding rule
HIGH severity (CVSS 7.0-8.9)
What every action level means
Emergency Immediate action required. Criteria: CRITICAL + in CISA KEV (actively exploited) without patch, OR CRITICAL + EPSS > 30% without patch, OR CRITICAL + active threat signals without patch.
Act Now Prioritize within 24-48h. Criteria: in KEV with patch available, OR CRITICAL + public POC, OR HIGH + EPSS > 10%, OR CRITICAL + active threat, OR any CRITICAL severity.
This Week Schedule remediation this week. Criteria: HIGH severity (CVSS 7.0-8.9). Patch within normal change window.
This Month Plan within 30 days. Criteria: MEDIUM severity (CVSS 4.0-6.9), lower exploitation probability. Include in regular patch cycle.
Monitor Track and reassess. Criteria: LOW severity (CVSS 0.1-3.9), minimal exploitation risk. No immediate action needed.

SSVC AssessmentENISA

SSVC Decision· derived
Scheduled
Exploitation· derived
None
System Exposure· derived
Open
Automatable· derived
Yes
Human Impact
High

Priority Score

41
Low Medium High Critical
KEV: 0
EPSS: 0
CVSS: +41
PoC: 0
Weaponized: 0
Threat intel: 0
Gov advisory: 0

Attack Technique

Denial of Service attacks render applications or systems unavailable by overwhelming resources or triggering failure conditions.

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

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