CVE-2026-23631: Analyzing “DarkReplica” and the Redis Use-After-Free Primitive

A sophisticated vulnerability in Redis, identified as CVE-2026-23631 and colloquially named “DarkReplica,” has surfaced, exposing authenticated deployments to Remote Code Execution (RCE). This flaw stems from a complex Use-After-Free (UAF) condition residing within the interaction between the replication subsystem and the Lua execution engine. The vulnerability was notably demonstrated by security researcher Yoni Sherez during the ZeroDay event.

The implications of this flaw are profound; as seen in the Cloud 2025 competition, it demonstrates how the orchestration of Redis’s internal Lua functions and its replication logic can be weaponized to achieve full host compromise.

Technical Breakdown: The Intersection of Replication and Lua

The attack vector targets Redis instances where the adversary has already obtained valid authentication credentials. The exploitation begins by leveraging the SLAVEOF command, which allows an attacker to force the target Redis instance to act as a replica of a malicious controller server.

Once the replication relationship is established, the attacker can manipulate the synchronization process to trigger unsafe memory management within the Redis Lua functions engine. To understand why this occurs, we must look at how Redis handles its dual Lua execution models: the legacy EVAL/EVALSHA engine and the modern, persistent FUNCTION LOAD/FCALL engine.

While Redis implements sandboxing to prevent malicious Lua scripts from escaping their environment, its single-threaded event loop introduces a subtle architectural edge case. To prevent long-running scripts from completely blocking the server, Redis utilizes a hook mechanism—specifically processEventsWhileBlocked()—to periodically process pending events and handle timeouts.

The vulnerability lies in a logic oversight: while most client-initiated commands are restricted while a Lua script is running, replication traffic from a master/controller is not. This allows for a critical race condition.

The Use-After-Free Mechanism

An attacker can initiate a “slow” Lua function (for example, an infinite loop) to hold the execution context open. Simultaneously, the malicious master triggers a FULLRESYNC command. During this synchronization phase, Redis attempts to refresh its state by calling functionsLibCtxClearCurrent(). This function proceeds to free the current functions library context and, crucially, releases the global lua_State object:

void functionsLibCtxClearCurrent(int async) {
    functionsLibCtxFree(curr_functions_lib_ctx);
    dictRelease(engines); // This releases the lua_State
    functionsInit();
}

When the execution flow eventually returns to the still-running Lua function, the function attempts to continue its operations using a pointer to a lua_State that has already been deallocated. This is a textbook Use-After-Free condition, providing the attacker with a primitive to corrupt heap memory.

Heap Manipulation and Achieving RCE

Exploiting this requires surgical precision because Redis utilizes jemalloc for memory management. Attackers must perform “heap spraying” or carefully timed allocations to reclaim the freed memory region with attacker-controlled data. By using Lua primitives like tostring(), an attacker can leak heap addresses to defeat ASLR (Address Space Layout Randomization).

A common strategy involves freeing a Lua object (such as a coroutine) and immediately reallocating that memory with a controlled string:

local a = coroutine.create(function() end)
local addr = tostring(a) -- Leak address
a = nil
collectgarbage("collect") -- Trigger deallocation
a = "AAAAAA..." -- Reallocate the same memory slot with controlled data

To stabilize the exploit and avoid immediate crashes, attackers often pivot to a separate Lua state via coroutines. This provides a stable environment to construct arbitrary read/write primitives by manipulating Lua table internals. The ultimate goal is to overwrite critical function pointers. A highly reliable path involves targeting the lua_State->l_G->frealloc pointer, which directs the custom memory allocator. By redirecting this to the system() function and controlling its arguments, the attacker can jump directly to arbitrary command execution:

write(fake_l_G + offsetof(global_State, frealloc), system);
write(fake_l_G + offsetof(global_State, ud), command_payload_addr);
coroutine.resume(co); // Execution triggers the system() call

Remediation and Mitigation

Redis released official patches on May 5, 2026, to address this vulnerability. Users should immediately audit their versions and upgrade to the following fixed releases:

  • 7.2.x: Upgrade to 7.2.14
  • 7.4.x: Upgrade to 7.4.9
  • 8.2.x: Upgrade to 8.2.6
  • 8.4.x: Upgrade to 8.4.3
  • 8.6.x: Upgrade to 8.6.3

For environments where immediate patching is not feasible, we recommend the following defense-in-depth measures:

  1. Strict Authentication: Ensure that all Redis instances require strong, unique credentials to prevent unauthorized access to the SLAVEOF command.
  2. Network Segmentation: Restrict replication traffic to known, trusted master/replica IP ranges via firewall rules.
  3. Disable Unused Features: If your application does not require Lua scripting, consider disabling the Lua engine to reduce the attack surface.

Given the ubiquitous role of Redis in modern microservices and cloud-native stacks, “DarkReplica” represents a high-risk threat for lateral movement within a cluster. Prompt patching is the only definitive solution.

Related Articles

Back to top button