<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title type="text"><![CDATA[RubySec]]></title>
  <subtitle type="text"><![CDATA[Providing security resources for the Ruby community]]></subtitle>
  <link href="https://rubysec.com/atom.xml" rel="self"/>
  <link href="https://rubysec.com/" rel="alternate" hreflang="en" />
  <updated>2026-10-06T19:26:51+00:00</updated>
  <id>https://rubysec.com/</id>
  <author>
    <name><![CDATA[RubySec]]></name>
    
  </author>
  <generator uri="https://jekyllrb.com/">Jekyll</generator>

  
  <entry>
    <title type="html"><![CDATA[GHSA-wr87-m4jw-29x5 (dalli): Per-request raw and the JSON serializer don't prevent unsafe deserialization]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/GHSA-wr87-m4jw-29x5/"/>
    <id>https://rubysec.com/advisories/GHSA-wr87-m4jw-29x5</id>
    <updated>2026-10-05T00:00:00+00:00</updated>
    <content type="html"><![CDATA[1. Per-request `raw: true` was ignored by some read methods, which still
   ran the configured serializer's `load` (Marshal by default) on values
   whose flags say they're serialized: in 5.1 and 5.2, `get_multi`,
   `get_multi_cas`, `get_multi_with_metadata`, `get_cas` and
   `get_with_metadata`; in 5.0, `get_with_metadata`; in 4.x, `get`,
   `gat` and `fetch` with the binary protocol, and `get_with_metadata`;
   in 3.x, `get`, `gat` and `fetch`.
2. `serializer: JSON` resolves to `JSON.load`. With the json gem before
   3.0, `JSON.load` honors `json_class` when the json additions are
   loaded, so a crafted value can instantiate classes that define
   `json_create`.

Exploiting either requires write access to the memcached instance and
an application relying on per-request `raw: true` or `serializer: JSON`
to avoid unsafe deserialization. Patched versions add
`Dalli::JSONSerializer`, which reads with `JSON.parse`.

The first fix (5.2.1, 5.1.3, 5.0.9, 4.3.6 and 3.2.12) was incomplete:
on 5.0, 4.3 and 3.2, `cas` and `cas!` (and `fetch_with_lock` on 5.0,
and on 4.3 with the meta protocol) still deserialized values read with
`raw: true`, and on every line but 3.2 a raw read still honored flags a
reply carried unasked. Both are fixed in 5.2.2, 5.1.4, 5.0.10, 4.3.7
and 3.2.13.

### Workarounds

Use a serializer that only parses data, such as one wrapping
`JSON.parse`, instead of `serializer: JSON`.]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[GHSA-w39f-xq2m-4g8x (dalli): Forking can resend buffered memcached requests and desynchronize the parent's connection]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/GHSA-w39f-xq2m-4g8x/"/>
    <id>https://rubysec.com/advisories/GHSA-w39f-xq2m-4g8x</id>
    <updated>2026-10-05T00:00:00+00:00</updated>
    <content type="html"><![CDATA[Dalli buffered request bytes in Ruby's IO write buffer, and quiet
(`multi`) blocks don't flush until they end. When the process forks,
the child inherits the buffer, and Ruby flushes it when the child closes
or finalizes the socket, even if the child never uses Dalli, so the
request is sent twice: a buffered write is applied twice, or a buffered
non-quiet request leaves the parent's connection off by one reply, so
later reads return the previous key's value. Affects 4.2.0 and later.

With TLS, the child's close sends close_notify on the shared connection
and tears down the parent's session. Affects all versions with TLS.

Applications that fork while threads use a shared client are affected
(pre-forking servers, job runners).

The first fix was incomplete on 4.3.6 and 3.2.12: when another
library's fork hook (such as connection_pool's, loaded before Dalli) ran
first in the child, the parent's TLS session could still be ended, and
4.3.6's write buffer kept a reference to the caller's value string with
the meta protocol. Both are fixed in 4.3.7 and 3.2.13.

### Workarounds

Call `close` on Dalli clients before forking, outside any quiet block.]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[GHSA-p6pm-ch9v-44vx (dalli): Pipelined get_multi can return another key's value after an error reply]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/GHSA-p6pm-ch9v-44vx/"/>
    <id>https://rubysec.com/advisories/GHSA-p6pm-ch9v-44vx</id>
    <updated>2026-10-05T00:00:00+00:00</updated>
    <content type="html"><![CDATA[Dalli's pipelined reply parser treated any reply line without a value
body (for example `CLIENT_ERROR` or `SERVER_ERROR`) as the `MN` that
ends the batch. It stopped reading that server's replies and left the
rest on the connection, where later commands read them as their own
replies, so a later `get` could return a different key's value.

memcached answers `CLIENT_ERROR` for a key over 250 bytes on the wire.
Dalli checked key length in characters, before base64-encoding keys
that need it, so a key of under 250 characters could still be too long.
If any part of a cache key comes from user input, a user can trigger
this and, in an application that caches per-user data, see another
user's data. Affects multi-server `get_multi` (including Rails
`read_multi`), `get_multi` with a block, and `get_multi_cas`, with the
meta protocol (3.2.0 and later; the default since 5.0.0).

With the binary protocol (the default before 5.0), the same over-long
key made memcached drop the connection, and `get` or `get_multi` with
it retried forever, so a user-supplied key could hang requests.

### Workarounds

Keep user-controlled cache keys well under 250 bytes, for example by
hashing them.]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[GHSA-m252-9cgf-vx2w (dalli): With a namespace, a retried request reads or writes a different key]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/GHSA-m252-9cgf-vx2w/"/>
    <id>https://rubysec.com/advisories/GHSA-m252-9cgf-vx2w</id>
    <updated>2026-10-05T00:00:00+00:00</updated>
    <content type="html"><![CDATA[When a client is configured with a `namespace`, a request that hits a
transient network error (a timeout, or a connection closed by memcached
or a proxy, such as stale connections after a memcached restart) was
retried with the namespace applied a second time, so `app:x` became
`app:app:x`. A retried read could return a different key's value, and a
retried write could overwrite a different key. Where cache keys include
user input, a user who can choose a key of the form `app:<something>`
can arrange for another user's retried read to return attacker-chosen
data.

Affected: every single-key operation since 5.0.3, single-server
`get_multi` since 5.1.0, and `get_with_metadata` and `fetch_with_lock`
since 4.1.0. Clients without a namespace are not affected, and 3.2.x is
not affected.

### Workarounds

Don't configure a `namespace`; prefix keys in application code instead.]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[GHSA-4qp6-2jcr-596v (dalli): Routing tokens can inject meta protocol flags, and failed requests can retry forever]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/GHSA-4qp6-2jcr-596v/"/>
    <id>https://rubysec.com/advisories/GHSA-4qp6-2jcr-596v</id>
    <updated>2026-10-05T00:00:00+00:00</updated>
    <content type="html"><![CDATA[1. `p_token` and `l_token` were checked only for CR, LF and NUL. A token
   containing spaces added arbitrary meta flags to the command: for
   example changing an item's TTL on a read, creating stub items on a
   miss, turning a delete into a stale tombstone, choosing `incr`'s
   initial value, or reading a different key. Affects 5.1.0 and later.
2. Failed requests were retried without a limit. Each retry reconnected
   successfully, which reset the failure count, so `socket_max_failures`
   was never reached and requests to a server that accepts connections
   but never replies (or drops the connection on a request) hung
   forever. Affects all versions.
3. Errors raised by application code inside a `get_multi` block
   (`Errno::*`, `Timeout::Error`) were treated as socket errors and
   retried the whole `get_multi`, causing duplicate yields, swallowed
   exceptions, or an endless loop. Affects 4.x and 5.x.

### Workarounds

Don't pass untrusted input as a routing token.]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[GHSA-3553-vcg5-72jw (dalli): Unbounded decompression and reply sizes allow memory exhaustion]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/GHSA-3553-vcg5-72jw/"/>
    <id>https://rubysec.com/advisories/GHSA-3553-vcg5-72jw</id>
    <updated>2026-10-05T00:00:00+00:00</updated>
    <content type="html"><![CDATA[1. Values flagged as compressed were inflated with no size limit. A
   ~130 KB stored item expands to 128 MB on read (about 1000:1),
   regardless of the client's `compress` or `serializer` settings.
2. The size in a reply (a meta `VA <size>`, or a binary body length) was
   used to read or buffer that many bytes, so a hostile or compromised
   server could make the client allocate gigabytes.

Exploiting either requires write access to the memcached instance (a
shared or exposed instance, another tenant), or a malicious server or
proxy. Patched versions add a `decompressed_max_bytes` option (default
128 MiB) and reject reply sizes over 1 GiB.]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CVE-2026-67989 (ruby_llm): Polynomial-Time Regular Expression Denial of Service (ReDoS) vulnerability]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/CVE-2026-67989/"/>
    <id>https://rubysec.com/advisories/CVE-2026-67989</id>
    <updated>2026-10-01T00:00:00+00:00</updated>
    <content type="html"><![CDATA[crmne/ruby_llm at commit fa6f279847d6d7027814539d9c0dfc3bbdfd2a83
contains a polynomial-time regular expression denial-of-service
condition in Mistral model capability matching on Ruby 3.1.x.]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CVE-2026-67987 (ruby_llm): Polynomial-Time Regular Expression Denial of Service (ReDoS) vulnerability]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/CVE-2026-67987/"/>
    <id>https://rubysec.com/advisories/CVE-2026-67987</id>
    <updated>2026-10-01T00:00:00+00:00</updated>
    <content type="html"><![CDATA[crmne/ruby_llm at commit fa6f279847d6d7027814539d9c0dfc3bbdfd2a83
contains polynomial-time regular expression denial-of-service
conditions in think-tag response parsing on Ruby 3.1.x.
A malicious or anomalous model response containing many unterminated
tags can cause excessive CPU consumption in two consecutive
regular expressions and delay chat-completion processing.]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CVE-2026-12545 (hammer_cli): hammer_cli - Insecure interpolation of the $EDITOR environment variable]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/CVE-2026-12545/"/>
    <id>https://rubysec.com/advisories/CVE-2026-12545</id>
    <updated>2026-10-01T00:00:00+00:00</updated>
    <content type="html"><![CDATA[A flaw was found in rubygem-hammer_cli. A command injection vulnerability
exists in Hammer CLI and the Railties (Ruby on Rails) component
distributed with Satellite due to the insecure interpolation of the
$EDITOR environment variable into the Ruby system() method.
By passing a single interpolated string to system(), the application
invokes a system shell (/bin/sh) that interprets shell
metacharacters (e.g., ;, |, &).]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[GHSA-42qh-8mx8-7wqm (rack-proxy): HTTP response smuggling via ambiguous backend response framing in rack-proxy 1.x]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/GHSA-42qh-8mx8-7wqm/"/>
    <id>https://rubysec.com/advisories/GHSA-42qh-8mx8-7wqm</id>
    <updated>2026-09-25T00:00:00+00:00</updated>
    <content type="html"><![CDATA[## Summary

rack-proxy 1.0.0 through 1.0.2 can forward an incorrect Content-Length
when a backend response contains both Transfer-Encoding and Content-Length.
Net::HTTP removes chunked framing from the body, while rack-proxy
strips Transfer-Encoding but retains the backend-supplied Content-Length.
This affects both the default streaming mode and streaming: false.

## Impact and Preconditions

A malicious, compromised, or attacker-influenced backend can supply
a length shorter than the dechunked body. When a frontend Rack handler
trusts this length and uses persistent connections, surplus bytes
can be interpreted as a subsequent HTTP response, allowing response-queue
poisoning and potentially affecting intermediaries or caches.

The reporter demonstrated downstream desynchronization with
WEBrick 1.9.2 via Rackup::Handler. Other handlers may close or
reframe the response; end-to-end exploitability depends on the
deployment. The inconsistent Rack response was confirmed in both
streaming modes. No opt-in setting is needed for the vulnerable
response handling.

## Credit

Thanks to oss-security-shop for privately reporting the
vulnerability and providing a detailed reproduction.]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[GHSA-6wmv-xq9m-fmp7 (dalli): Memcached command injection through numeric arguments to incr/decr and fetch_with_lock]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/GHSA-6wmv-xq9m-fmp7/"/>
    <id>https://rubysec.com/advisories/GHSA-6wmv-xq9m-fmp7</id>
    <updated>2026-09-24T00:00:00+00:00</updated>
    <content type="html"><![CDATA[Dalli's meta protocol request formatter wrote some numeric arguments
into memcached commands without converting them to integers. If an
application passes an attacker-controlled String to one of these
arguments, CRLF sequences in it are sent to memcached as additional
commands on the same connection, letting the attacker run arbitrary
memcached commands, such as overwriting keys or running `flush_all`.

The affected arguments are the `default` (initial value) argument of
`Dalli::Client#incr` and `#decr`, and the `lock_ttl` and
`recache_threshold` arguments of `Dalli::Client#fetch_with_lock`
(4.2.0 and later).

In 3.2.x and 4.x, only clients created with `protocol: :meta` are
affected; the default binary protocol is not. All 5.x configurations
are affected.

An application is only exploitable if untrusted input reaches one of
these arguments.

### Workarounds

Convert values to integers before passing them, e.g.
`Integer(params[:initial], 10)`. On 3.2.x and 4.x, use the default
binary protocol instead of `protocol: :meta`.]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[GHSA-p8jg-8p9f-pgmr (faraday-http-cache): Cache entries deserialized with JSON.load can instantiate arbitrary classes named by an origin server]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/GHSA-p8jg-8p9f-pgmr/"/>
    <id>https://rubysec.com/advisories/GHSA-p8jg-8p9f-pgmr</id>
    <updated>2026-09-15T00:00:00+00:00</updated>
    <content type="html"><![CDATA[faraday-http-cache stores cached responses with the JSON module by
default and reads them back with JSON.load, which honours the
json_class key and calls json_create on the named class. Response
headers are stored verbatim inside the cache entry, so an origin
server that returns a json_class response header causes that class
to be instantiated in the client process on the next cache hit. Any
application that uses the middleware to fetch URLs it does not
fully control is affected with the default configuration, through
both the ByUrl and ByVary strategies.

NOTE: Versions 2.0.0 through 2.7.0 were confirmed by the reporter;
the 1.x line was not tested but uses the same deserialization path.

## CREDIT

Reported by Matthew Mongeau (Ruby Central / Project Glasswing).]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[GHSA-c33f-42f2-gwcc (faraday-http-cache): Shared cache serves responses to authenticated requests to other callers]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/GHSA-c33f-42f2-gwcc/"/>
    <id>https://rubysec.com/advisories/GHSA-c33f-42f2-gwcc</id>
    <updated>2026-09-15T00:00:00+00:00</updated>
    <content type="html"><![CDATA[faraday-http-cache acts as a shared cache by default (shared_cache: true).
The ByUrl strategy keys entries on method and URL and treats a cached
response without a Vary header as matching every request, and the
ByVary strategy relies on the origin listing Authorization in Vary.
A response to a request that carried an Authorization header is
therefore stored and served to later requests from different callers
whenever the origin omits Vary and does not mark the response private.

RFC 9111 section 3.5 requires a shared cache not to reuse such a
response unless it carries public, must-revalidate or s-maxage. The
middleware did not implement that rule.

NOTE: Versions 2.0.0 through 2.7.0 were confirmed by the reporter;
the 1.x line was not tested.

## CREDIT

Reported by Matthew Mongeau (Ruby Central / Project Glasswing).
RFC 9111 section 3.5.]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CVE-2026-88030 (mongo): MongoDB Ruby Driver - Improper neutralization of special elements in data query logic in the GridFS component]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/CVE-2026-88030/"/>
    <id>https://rubysec.com/advisories/CVE-2026-88030</id>
    <updated>2026-09-10T00:00:00+00:00</updated>
    <content type="html"><![CDATA[Improper neutralization of special elements in data query logic in
the GridFS component of the MongoDB Ruby Driver can cause a
caller-supplied structured file identifier to be interpreted as a
query condition rather than as a literal identifier. An authenticated
user who can influence the identifier passed by an affected application
may obtain stored file content beyond the intended target or cause
all GridFS file chunks in the affected bucket to be removed,
rendering stored file content unreadable.]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CVE-2026-85396 (rubyzip): path traversal vulnerability in pre-3.4.0 rubyzip gem]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/CVE-2026-85396/"/>
    <id>https://rubysec.com/advisories/CVE-2026-85396</id>
    <updated>2026-09-03T00:00:00+00:00</updated>
    <content type="html"><![CDATA[rubyzip versions before 3.4.0 contain a path traversal vulnerability
in Zip::Entry#extract that fails to properly validate extraction
paths using prefix comparison without trailing separators. Attackers
can craft archive entries with names like ../upload_backup/owned.sh
to write files outside the intended extraction directory into
sibling paths sharing the destination prefix.]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[GHSA-g7vv-4mjj-6fgm (alchemy_cms): Account Takeover & Privilege-Escalation To Admin via Stored XSS in Menu Node Name Rendered in Page Properties Configure Dialog]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/GHSA-g7vv-4mjj-6fgm/"/>
    <id>https://rubysec.com/advisories/GHSA-g7vv-4mjj-6fgm</id>
    <updated>2026-09-02T00:00:00+00:00</updated>
    <content type="html"><![CDATA[An improper input sanitization vulnerability in the Page Properties
menu node rendering allows Author-level users to inject stored
JavaScript that executes in an Admin's browser when they open the
Configure dialog for a page containing the malicious node. The
payload executes with the Admin's session privileges, allowing
an attacker to perform administrative actions and create an
attacker-controlled administrator account, resulting in full
account takeover and privilege escalation.]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[GHSA-4qhx-6wrv-5hg2 (alchemy_cms): Account Takeover & Privilege-Escalation To Admin via Stored XSS in Menu Node Name Rendered in Admin Configure Dialog Page Content]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/GHSA-4qhx-6wrv-5hg2/"/>
    <id>https://rubysec.com/advisories/GHSA-4qhx-6wrv-5hg2</id>
    <updated>2026-09-02T00:00:00+00:00</updated>
    <content type="html"><![CDATA[An improper input sanitization vulnerability in the menu node name
rendering allows Author-level users to inject stored JavaScript
that executes in an Admin's browser when they open the configure
dialog for a page referencing the malicious node. The payload
executes with the Admin's session privileges, allowing an attacker
to perform administrative actions and create an attacker-controlled
administrator account, resulting in full account takeover and
privilege escalation.]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CVE-2026-81097 (rails-mcp-server): The execute_ruby tool is documented as a read-only Ruby sandbox]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/CVE-2026-81097/"/>
    <id>https://rubysec.com/advisories/CVE-2026-81097</id>
    <updated>2026-08-27T00:00:00+00:00</updated>
    <content type="html"><![CDATA[The execute_ruby tool is documented as a read-only Ruby sandbox
and is enforced by a pattern denylist together with replacements
for the process-spawning methods on Kernel.

The pseudo-terminal library's spawn entry points are neither in the
denylist nor replaced, so a normal tool call could reach them and
start a shell, executing commands as the account running the server
and outside  the guarded methods.

The denylist was introduced with the tool in 1.4.0 and
never covered those entry points through 1.6.0.

Version 1.6.1 restricts the requires the sandbox permits to a
data-only list and blocks dynamic dispatch to execution entry
points.

2.0.0 removes the tool.]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CVE-2026-80213 (resolv): CVE-2026-80213 - Hostname validation bypass]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/CVE-2026-80213/"/>
    <id>https://rubysec.com/advisories/CVE-2026-80213</id>
    <updated>2026-08-27T00:00:00+00:00</updated>
    <content type="html"><![CDATA[An application that checks a hostname against an allow list or an
SSRF filter and then resolves it can be made to look up a domain
other than the one it checked. The string that passes validation
and the name that reaches the network are not the same, so the
connection can end up at a host the application never approved.
This requires a hostname that exceeds the DNS length limits, so
validation that rejects names longer than 255 octets, or labels
longer than 63 octets, is not affected.

## Credits

Thanks to dalifit for discovering these issues.]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CVE-2026-80212 (resolv): CVE-2026-80212 - Memory exhaustion through malicious DNS responses]]></title>
    <link rel="alternate" href="https://rubysec.com/advisories/CVE-2026-80212/"/>
    <id>https://rubysec.com/advisories/CVE-2026-80212</id>
    <updated>2026-08-27T00:00:00+00:00</updated>
    <content type="html"><![CDATA[An application that resolves a hostname an attacker can influence,
such as a webhook target or a user-supplied URL, can be made to
consume memory without bound. The attacker points a domain at a
name server they control and returns responses that the library
retains permanently. Repeated lookups grow the process until it
runs out of memory and the service stops.

## Credits

Thanks to dalifit for discovering these issues.]]></content>
  </entry>
  
</feed>
