A quiet block, an interrupted get_multi, or a value containing CR/LF can return another key's value
Published: October 28, 2026
SECURITY IDENTIFIERS
- GHSA: GHSA-5xvx-r8rg-5qm2
- Vendor Advisory: https://github.com/petergoldstein/dalli/security/advisories/GHSA-5xvx-r8rg-5qm2
GEM
PATCHED VERSIONS
~> 3.2.15
~> 4.3.9
~> 5.0.12
~> 5.1.6
>= 5.2.4
DESCRIPTION
Three ways a connection can get out of step with memcached, so that a request reads the reply meant for a different request. Reads can then return another key's value, which can expose one user's cached data to another.
-
A
quiet(ormulti) block on one thread or fiber. memcached still replies to a quiet request that fails, for example anaddof a key that already exists. If another thread or fiber uses the sameDalli::Clientwhile the block is open, its next request reads that reply as its own. This happens with the default options and a client shared across threads or fibers. Clients on 5.2 withdefer_drain: truearen't affected. It affects every supported line, with both protocols; with the binary protocol (3.2 and 4.3) the connection stays out of step even after the block ends. -
A pipelined
get_multiinterrupted by a non-network exception (its block raising or breaking,Timeout.timeout, or a value that can't be deserialized). A laterget_multilarge enough to use the interleaved path parses the old replies first and leaves its own on the connection. It affects 4.3 and later. -
A value containing CR/LF, on 3.2 with
protocol: :meta. 3.2's meta protocol read a value up to the first CRLF instead of by its size, so a stored value containing a crafted reply was returned for a later read of a different key, possibly with flags that cause it to be deserialized (Marshal by default). It affects 3.2.0 to 3.2.14 withprotocol: :meta.
Workarounds
- Don't share a client across threads or fibers while using
quiet/multi; use a connection pool. On 5.2,defer_drain: trueavoids the first issue. - Avoid raising or breaking out of a
get_multiblock, and avoid wrappingget_multiinTimeout.timeout. - On 3.2, use the binary protocol (the default).
RELATED
- https://github.com/petergoldstein/dalli/security/advisories/GHSA-5xvx-r8rg-5qm2
- https://github.com/petergoldstein/dalli/commit/322a496
- https://github.com/petergoldstein/dalli/commit/0a34a51
- https://rubygems.org/gems/dalli/versions/5.2.4
- https://github.com/petergoldstein/dalli/releases/tag/v5.2.4
- https://rubygems.org/gems/dalli/versions/5.1.6
- https://github.com/petergoldstein/dalli/releases/tag/v5.1.6
- https://rubygems.org/gems/dalli/versions/5.0.12
- https://github.com/petergoldstein/dalli/releases/tag/v5.0.12
- https://rubygems.org/gems/dalli/versions/4.3.9
- https://github.com/petergoldstein/dalli/releases/tag/v4.3.9
- https://rubygems.org/gems/dalli/versions/3.2.15
- https://github.com/petergoldstein/dalli/releases/tag/v3.2.15
