CVE-2026-81934: Redis TLS pending-list use-after-free (public RCE PoC)

CVE-2026-81934: Redis TLS pending-list use-after-free (public RCE PoC)

How to fix CVE-2026-81934: upgrade Redis to 8.2.9, 8.4.6, 8.6.6, 8.8.2, or 8.10.1

3 min read583 words
Contents

Redis assigned CVE-2026-81934 today to a TLS-only use-after-free that already shipped in the 2026-08-17 SECURITY cut (8.2.9, 8.4.6, 8.6.6, 8.8.2, 8.10.1). The release notes named the bug without a CVE id. A public PoC now turns that stale listNode into shell as the redis-server process over the normal TLS command path. If you run Redis with TLS and missed that cut, this is the upgrade.

Who is not in scope

Skip the pager if any of these hold:

  • The binary was built without TLS (BUILD_TLS off) and you do not listen with tls-port. The bug lives in tlsProcessPendingData() in src/tls.c; plaintext Redis never enters that list.
  • You already run 8.2.9+, 8.4.6+, 8.6.6+, 8.8.2+, or 8.10.1+ (the 2026-08-17 SECURITY releases). Commit 6d088c3 is in those trains.
  • Managed Redis where the vendor confirms the Aug 17 SECURITY builds (or newer) are what you get. Confirm the exact server version; do not assume from the control-plane UI alone.

What this is not

This is not a plaintext Redis RCE, not the CMSketch RDB OOB write from the same cut (that one is CVE-2026-62356), and not an internet worm that works against every open 6379. It needs a TLS-enabled server and a client that can speak Redis over TLS long enough to shape the pending-data list.

What broke

tlsProcessPendingData() walked the TLS pending-data list with Redis's adlist iterator. listNext() caches current->next before returning the current node. While the current connection's read handler runs, a command can close a different pending TLS connection (the commit message cites CLIENT KILL as the example). That close path frees the victim's pending-list node. If the iterator had already cached that node as next, the following listNext() dereferences freed memory.

The fix stops using a pre-cached iterator. It drains a bounded count of heads: detach via tlsPendingRemove() before tlsHandleEvent(), then re-read listFirst() each turn so no list node pointer is held across a handler call. Cherry-picked from 98ff29b into the stable trains as 6d088c3 (authored 2026-08-17).

v12-security published a PoC against the official amd64 Redis 8.8.0 image with TLS on. It grooms the pending list with multiple TLS clients, uses Lua timeout / Pub/Sub traffic to re-enter the event loop, reclaims the freed node, and ends in arbitrary command execution as the Redis uid. The PoC is timing- and heap-layout-sensitive; treat that as evidence the UAF is weaponizable, not as a reliability guarantee for every build.

Operator check

On each Redis host (or pod):

redis-server --version
redis-cli -p <port> INFO server | egrep 'redis_version|tcp_port'
# if you use TLS on a dedicated port:
redis-cli --tls -p <tls-port> INFO server | egrep 'redis_version'
grep -E '^(port|tls-port|tls-cert-file|tls-key-file)' /etc/redis/redis.conf 2>/dev/null

You are exposed when tls-port (or equivalent) is set and the version is below the fixed trains above. A non-zero tls-port with an Aug 17 SECURITY build or newer is the clear line.

How to fix

Upgrade Redis Open Source to one of:

  • 8.2.9
  • 8.4.6
  • 8.6.6
  • 8.8.2
  • 8.10.1

Those builds also carry the rest of the 2026-08-17 SECURITY batch (including CVE-2026-62356). Prefer the newest train you already run; do not jump majors just for this CVE unless you planned to.

After upgrade, re-check redis-server --version and confirm TLS listeners still come up. Rolling restart replicas before primaries if you run replication.

References

Continue reading

All posts