EVAL or EVALSHA can arrange object references and garbage-collector timing so that memory still referenced by a live object is freed and then reused, corrupting the Lua virtual machine and the surrounding Redis heap. From there the attacker escapes the Lua sandbox into native execution inside the Redis process, and from that process onto the host. Redis rates it 9.9 Critical, not a perfect 10, and the distinction matters: the vector is AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H. Privileges are required (PR:L), so this is not literally an unauthenticated bug. The catch is that Redis ships with no authentication configured, so a large share of internet-exposed instances accept commands from anyone who can reach the port.
The vulnerability was reported through Pwn2Own Berlin in May 2025 by researchers working with Wiz and the Zero Day Initiative, and Redis published fixed builds on 3 October 2025. This piece is about the mechanism, not a reproduction. We do not publish exploit primitives. We explain why a garbage-collector race in an embedded scripting language becomes native code execution, why the default configuration turns a privileged-access bug into a practically open one, and why this specific data store sits under so much of the AI and platform infrastructure that teams stood up quickly in the last two years. Verifiable security.
The bug in one paragraph
Redis embeds a Lua interpreter so that clients can run small server-side scripts atomically. Scripts are meant to live inside a sandbox: a restricted Lua environment with dangerous standard-library functions stripped out, so a script can read and write keys but cannot touch the filesystem, spawn processes, or reach into the host. RediShell defeats that boundary not by finding a missing restriction, but by corrupting the memory the interpreter itself runs on. The Lua engine, like most managed runtimes, uses a garbage collector to reclaim objects that are no longer reachable. The flaw is that a carefully constructed script can convince the collector that an object is dead and free its memory while another live reference to that same memory still exists. That is the textbook shape of a use-after-free: free, then use. Once the attacker controls what gets written into the freed-then-reused region, the invariants the interpreter relies on are broken, and the sandbox stops being a sandbox because the machine enforcing it has been overwritten.
How a garbage-collector race becomes a corruption primitive
The interesting part is the timing. A use-after-free is only useful if the attacker can win the window between the free and the use, and can control what lands in the reclaimed memory. In an interpreted language with automatic memory management, both of those are shaped by how the garbage collector decides what is reachable. A script that manipulates object references, holds a reference the collector fails to account for, and then forces a collection cycle at the right moment can drive the engine to release memory that is still in use. The classic technique is to spray the heap with attacker-sized objects so that the freed slot is predictably reallocated with content the attacker chose, then trigger the code path that dereferences the stale reference. At that point the interpreter is reading a structure whose type or length fields the attacker now controls, which yields the primitives every memory-corruption exploit is built from: a controlled read, a controlled write, and eventually control over a function pointer or object metadata that the runtime trusts.
The shape of the race, not a working exploit. The sandbox is enforced by the same VM the corruption overwrites.
Why sandbox escape follows, and why native execution follows that
A scripting sandbox is only as strong as the integrity of the interpreter enforcing it. The Redis Lua sandbox works by removing dangerous globals and constraining what a script can name. None of that matters once the attacker can write to arbitrary memory, because the checks that implement the sandbox are just data and code in the same address space the corruption reaches. With a controlled write, an attacker can overwrite the metadata that the Lua runtime consults, redirect an internal function pointer, or forge an object whose behavior the engine invokes. The result is execution that is no longer bounded by Lua semantics at all: it is native code running inside the Redis server process, with whatever privileges that process holds. Because Redis is a single-threaded, in-process engine with the scripting VM embedded directly in the server, there is no separate sandbox process to contain the escape. Corrupting the Lua VM is corrupting Redis. From native execution in the Redis process, the usual host pivots follow: writing files if the process can, abusing the account Redis runs as, and using the foothold to reach the rest of the environment.
A scripting sandbox is only as strong as the integrity of the interpreter enforcing it. Once you can write to the VM's own memory, the sandbox is just more bytes to overwrite.
The authentication gap: required, yet usually absent
Be precise about the access requirement, because it is the difference between a manageable risk and a five-alarm one. The CVSS vector says PR:L: the attacker needs the ability to run a script, which means a session that is permitted to call EVAL or EVALSHA. On a properly configured instance, that is a privileged capability behind a password or an ACL. So it is wrong to call this an unauthenticated remote code execution bug in the abstract. The problem is what happens in practice. Redis ships with no requirepass and no restrictive ACL by default; an out-of-the-box instance treats any client that can open a TCP connection as fully authorized, including to run scripts. A very large number of Redis servers are exposed to untrusted networks with exactly that default in place, or bound to an interface that a wider network can reach than the operator assumed. For every one of those, the PR:L requirement is satisfied trivially, because there is no authentication step to satisfy. The honest framing is both halves at once: authentication is required by the design of the fix and the vector, and authentication is missing by default across much of the exposed fleet.
Why this lands hard on AI and platform infrastructure
Redis is not a niche cache anymore. It sits under a surprising amount of the infrastructure that teams built in a hurry over the last two years. It backs task and message queues for workers, session and rate-limit state for APIs, feature stores for models, and increasingly the vector-similarity and semantic-cache layers behind retrieval-augmented generation and large-language-model applications. A retrieval pipeline that caches embeddings, a queue that fans out inference jobs, a memory layer that holds conversation state: any of these may be a Redis instance that someone stood up inside a trusted network segment and never fastened down, on the reasonable-sounding assumption that it was internal. That assumption is exactly the exposure. Internal-only is a claim about network reachability, and network reachability is precisely what drifts as clusters, service meshes, and cloud peering evolve. When a component that everything defers to for state and coordination can be turned into host code execution by a client that can run a script, and when that client barrier is frequently just absent, the AI stack inherits a memory-corruption bug in its foundation. The blast radius is not one cache. It is the trust that every service placed in the store they all share.
How to recognize your exposure without firing an exploit
You can assess this from readable facts, none of which require sending a corrupting script.
- Version. The fix landed in Redis 6.2.20, 7.2.11, 7.4.6, 8.0.4, and 8.2.2, released on 3 October 2025. Any build earlier than the fixed release on its line carries the flaw. Fingerprint the exact version rather than trusting a package label.
- Reachability. Determine which instances answer from outside their intended segment. A Redis port reachable from an untrusted network is the precondition that makes the default-no-auth case exploitable.
- Authentication and ACLs. Check whether
requirepassis set and whether ACLs actually constrain who may call scripting commands. An instance with no password is one where thePR:Lbarrier does not exist. - Scripting availability. Confirm whether
EVALandEVALSHAare reachable for the identities that connect. If untrusted callers can run scripts, the path to the bug is open on an unpatched build.
What to do about it
Close the Lua use-after-free on your Redis fleet
- Upgrade to a fixed build. Move every instance to 6.2.20, 7.2.11, 7.4.6, 8.0.4, or 8.2.2 or later on its line. This is the actual fix; everything else is mitigation around an unpatched bug.
- Require authentication everywhere. Set
requirepassor, better, define ACLs so no instance treats an anonymous connection as authorized. This restores thePR:Lbarrier the default removes. - Restrict scripting for untrusted identities. Use ACLs to deny
EVAL,EVALSHA, and related scripting commands to any user that does not genuinely need them, shrinking who can reach the vulnerable engine at all. - Get Redis off untrusted networks. Bind to loopback or a private interface, enforce it with host and network controls, and verify reachability rather than assuming internal-only.
- Alert on anomalous scripting volume. A sudden rise in
EVALtraffic, unusual script sizes, or scripting from an identity that never scripted before is a high-signal indicator against a normally quiet surface. - Re-check the known-exploited catalog at publish time. This bug was not confirmed on the CISA KEV list at the time of writing. Given the exposure, treat catalog status as a live value and recheck it before you deprioritize.
How Celvex catches this
Find. Prove. Fix. Verify.
A read-only sweep locates reachable Redis instances, fingerprints the exact version against the fixed 6.2.20 / 7.2.11 / 7.4.6 / 8.0.4 / 8.2.2 line, and records whether authentication and scripting ACLs are in place, all without sending a single corrupting script.
An exposed, unpatched, or no-auth instance becomes an Ed25519-signed Proof Capsule carrying the host, the version evidence, and the configuration facts, reproducible offline by you or your auditor.
The capsule's remediation block names the steps: upgrade to the fixed build, set authentication, restrict scripting commands by ACL, and remove the instance from untrusted network reach.
A fresh sweep confirms the build is fixed, the authentication barrier is back, and the port is no longer exposed. The finding closes and the verified-fix event is recorded for the audit trail.
The lesson of RediShell is not that Lua scripting was a mistake, and it is not that Redis is uniquely fragile. It is that a boundary enforced in software is only as trustworthy as the memory safety of the thing enforcing it, and that a default which trades security for a smooth first-run experience becomes a fleet-wide liability once the software is everywhere. A roughly thirteen-year-old use-after-free that reaches native code through a scripting engine, on a data store that half the modern stack quietly depends on, is a reminder to ask the boundary question of the components you file under trusted infrastructure: what version, reachable from where, authenticated how, and who is allowed to run code inside it.
Verifiable security. Find it. Prove it. Fix it. Verify the fix held. That is what we ship.
Sources
Is a no-auth Redis holding your AI stack together?
Free Exposure Check, no signup required. We locate reachable Redis instances, fingerprint the version against the fixed builds, record whether authentication and scripting ACLs are in place, and ship a signed Proof Capsule for the highest-confidence finding.
Run a Free Scan →