MEDIUM 5.5

CVE-2026-54905: concurrent-ruby ReentrantReadWriteLock Integer Overflow Breaks Mutual Exclusion

A flaw in concurrent-ruby's ReentrantReadWriteLock allows a thread to incorrectly obtain a write lock after repeatedly acquiring a read lock 32,768 times. The lock mechanism uses a single integer to track hold counts, and this specific reentry threshold causes the read count to overflow into a bit flag reserved for write locks. As a result, a thread can be granted write lock status without the library actually preventing other threads from holding read locks simultaneously, breaking the mutual exclusion guarantee that write locks are supposed to provide. This creates a race condition where concurrent read and write access can occur unsafely.

Source data · NVD / CISA · public domain

CVSS
3.1 · 5.5 MEDIUM · CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
Weaknesses (CWE)
CWE-128
Affected products
1 configuration(s)
Published / Modified
2026-06-24 / 2026-06-26

NVD description (verbatim)

concurrent-ruby is a modern concurrency tools for Ruby. Prior to 1.3.7, Concurrent::ReentrantReadWriteLock can incorrectly grant a write lock after one thread acquires the read lock 32,768 times. The lock stores a thread's local read and write hold counts in one integer. The low 15 bits are used for the read hold count, and bit 15 is used as WRITE_LOCK_HELD. After 32,768 reentrant read acquisitions, the local read count crosses into the write-lock bit. try_write_lock then treats the thread as already holding a write lock and returns true without setting the global RUNNING_WRITER bit. This breaks the core mutual-exclusion guarantee: the caller is told it has a write lock, but other threads can still hold or acquire read locks at the same time. This vulnerability is fixed in 1.3.7.

2 reference(s) · View on NVD →

SEC.co analysis · AI-assisted, reviewed against source

Technical summary

concurrent-ruby versions prior to 1.3.7 contain a bit-packing vulnerability in ReentrantReadWriteLock. The implementation stores a thread's local read and write hold counts in a single 16-bit integer: the low 15 bits represent the read hold count, and bit 15 is the WRITE_LOCK_HELD flag. When a thread acquires a read lock 32,768 times (2^15), the read hold count overflows and sets bit 15. The try_write_lock method then misinterprets this state, believing the thread already holds the write lock and returning true without acquiring the global RUNNING_WRITER state. Consequently, other threads can simultaneously hold or acquire read locks while the calling thread believes it alone has exclusive write access. This violates the core contract of reader-writer locks and opens a window for data races and state corruption.

Business impact

Applications relying on concurrent-ruby's ReentrantReadWriteLock for protecting shared resources face potential data corruption and inconsistent state. The vulnerability manifests only after a high number of reentrant read acquisitions (32,768) on the same lock by a single thread, limiting real-world exposure in many use cases; however, workloads with intensive read-lock recycling or long-lived readers could trigger this condition. Confidentiality and integrity of protected data are at risk. For systems using concurrent-ruby in critical sections—such as in-memory caches, state machines, or coordination layers—undetected race conditions could lead to subtle bugs that are difficult to reproduce and diagnose.

Affected systems

concurrent-ruby versions before 1.3.7 are affected. The vulnerability is specific to the ReentrantReadWriteLock class and impacts any Ruby application that uses this library for synchronization, particularly those with threads that acquire read locks multiple times on the same lock instance. Systems running versions 1.3.7 and later are not affected.

Exploitability

Exploitation requires local code execution within the same Ruby process and knowledge of which locks and access patterns to target. An attacker would need to trigger the specific condition of 32,768 reentrant read lock acquisitions on a shared lock, then time a write lock request to coincide with concurrent read access. The attack is not remotely exploitable and demands precise conditions; however, in multithreaded applications where an attacker controls some threads, the barrier is lower. The high reentry count threshold makes accidental triggering unlikely in normal workloads, but deliberate exploitation in adversarial scenarios is feasible.

Remediation

Upgrade concurrent-ruby to version 1.3.7 or later. Verify the patch by checking the gem version in your Gemfile.lock or running `gem list concurrent-ruby`. No configuration changes or workarounds are required; the fix corrects the bit-packing logic to prevent read count overflow from corrupting the write lock flag. After patching, applications should be restarted to load the corrected library.

Patch guidance

Update your Gemfile to require concurrent-ruby >= 1.3.7, then run `bundle update concurrent-ruby`. For Ruby applications managed without Bundler, use `gem update concurrent-ruby` or install the patched version directly via `gem install concurrent-ruby -v 1.3.7`. Verify the installed version with `gem list concurrent-ruby`. If your application pins concurrent-ruby as a dependency, ensure all dependency constraints are relaxed to allow 1.3.7 or higher. Test the upgrade in a staging environment before deploying to production, particularly if your codebase relies heavily on ReentrantReadWriteLock.

Detection guidance

Review your Ruby application's use of concurrent-ruby, specifically instances where ReentrantReadWriteLock is created and used. Identify any code paths where a single thread acquires read locks on the same lock instance in a loop or recursive manner, counting toward the 32,768 threshold. Log or instrument lock acquisition and release to observe reentry counts. Check application logs for unexplained race conditions, data inconsistencies, or state corruption that correlate with high read-lock reentry. In development and staging, run stress tests with threads that aggressively reacquire read locks to trigger the overflow condition and confirm whether you are vulnerable.

Why prioritize this

This vulnerability rates MEDIUM severity due to its specificity: it requires a precise reentry threshold (32,768) and local execution context, limiting real-world exploitation. However, it directly undermines a core synchronization primitive, and any successful exploitation leads to data races with potential for corruption. Organizations using concurrent-ruby extensively for critical synchronization should prioritize the upgrade; those with lighter or different usage patterns can schedule it in a regular maintenance window. The fact that it is not on the KEV list reflects low demonstrated wild exploitation, but the integrity risk warrants timely patching.

Risk score, explained

CVSS 3.1 score of 5.5 reflects MEDIUM severity. The vector AV:L (Local) confirms the attacker must execute code on the same host and process. AC:L (Low complexity) acknowledges that once local execution is achieved, triggering the overflow is straightforward. PR:L (Low privilege) indicates an unprivileged user can execute code that triggers the condition. UI:N (No user interaction) means no victim action is needed. S:U (Unchanged scope) shows the impact is confined to the vulnerable application. C:H (High confidentiality impact) recognizes that read-write lock failure can expose sensitive data in protected sections. I:N (No integrity impact in CVSS calculation) reflects CVSS's conservative rating, though in practice data corruption is a real concern. A:N (No availability impact) acknowledges that the lock may not crash the process, but its guarantee is broken.

Frequently asked questions

Will this vulnerability affect my application if it does not explicitly use ReentrantReadWriteLock?

Only if your code directly uses ReentrantReadWriteLock from concurrent-ruby. If you use higher-level constructs like Mutex, Array#to_h, or other concurrency utilities provided by concurrent-ruby that do not rely on ReentrantReadWriteLock, this specific vulnerability does not apply. Examine your Gemfile and search your codebase for 'ReentrantReadWriteLock' to confirm.

What is the realistic likelihood of hitting the 32,768 reentry threshold?

In typical applications, reentry counts rarely exceed a few hundred. The threshold is hit only when a single thread acquires a read lock on the same instance at least 32,768 times without releasing it completely. This could occur in recursive functions, tight loops, or long-lived thread-local operations. Most codebases won't reach this limit under normal operation, but high-throughput or long-running reader threads could accumulate reentries over time.

What happens if I remain on an older version for a short time?

If you cannot immediately upgrade, audit your application's use of ReentrantReadWriteLock and, if present, limit concurrent reader threads on those locks or refactor to avoid deep reentry. However, this is a temporary measure. The risk of data races and corruption persists. Plan the upgrade to 1.3.7 as soon as possible, ideally within the next maintenance cycle.

Does this vulnerability require network access to exploit?

No. This is a local vulnerability requiring code execution within the same Ruby process. An attacker cannot exploit it remotely over a network. However, any mechanism that allows an untrusted user to run code in your Ruby application (e.g., unsafe deserialization, code injection, plugin system) becomes an exploitation vector.

This analysis is provided for informational and educational purposes. It is based on the CVE record and vendor advisory as of the publication date. Organizations should verify patch availability and compatibility within their environments before deployment. SEC.co does not provide warranty regarding the completeness or accuracy of this assessment. Consult the official concurrent-ruby security advisory and your organization's change management and testing procedures before implementing patches. Real-world impact may vary based on your specific application architecture and usage patterns. Source: NVD (public-domain), retrieved 2026-08-02. Analysis generated by SEC.co (claude-haiku-4-5).