CVE-2020-15888 Overview
CVE-2020-15888 is a memory corruption vulnerability in Lua through version 5.4.0 that occurs due to improper handling of the interaction between stack resizes and garbage collection. This flaw can lead to multiple memory safety issues including heap-based buffer overflow, heap-based buffer over-read, and use-after-free conditions.
Critical Impact
Attackers can potentially achieve arbitrary code execution by exploiting memory corruption conditions that arise when stack reallocation triggers garbage collection, corrupting stack pointers and memory references.
Affected Products
- Lua 5.4.0 and earlier versions
- Applications embedding the Lua interpreter
- Software utilizing Lua for scripting functionality
Discovery Timeline
- 2020-07-21 - CVE-2020-15888 published to NVD
- 2024-11-21 - Last updated in NVD database
Technical Details for CVE-2020-15888
Vulnerability Analysis
This vulnerability stems from a race condition between two critical Lua runtime operations: stack resizing and garbage collection. When the Lua interpreter needs to grow or shrink its stack, it performs memory reallocation. However, if garbage collection is triggered during this process, references held by the garbage collector may point to invalid or freed memory regions.
The interaction between these two subsystems was not properly synchronized, allowing for scenarios where:
- A stack resize operation begins and relocates the stack buffer
- Garbage collection runs before all internal references are updated
- The garbage collector accesses stale pointers referencing the old stack location
This results in heap-based buffer overflows when writing to relocated memory, out-of-bounds reads when accessing freed regions, and use-after-free conditions when dereferencing stale pointers.
Root Cause
The root cause lies in the ldo.c file within the Lua source code, specifically in the stack management functions. The luaD_shrinkstack function calculated a "good size" for the stack using an inadequate formula that could result in undersized stack allocations. Additionally, the checkstackp macro did not properly handle garbage collection cycles that could occur during stack reallocation.
The vulnerable code failed to maintain a minimum stack size during shrink operations and did not properly sequence the creation of CallInfo structures with stack size checks, allowing the garbage collector to observe inconsistent internal state.
Attack Vector
The vulnerability is exploitable over the network when applications accept and execute Lua scripts from untrusted sources. An attacker can craft malicious Lua code that manipulates stack depth and triggers garbage collection at precise moments to exploit the race condition. User interaction is required in the form of executing or loading the malicious script.
The following patches from the official Lua repository address the vulnerability:
Stack shrink size fix in ldo.c:
void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L);
- int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
+ int goodsize = inuse + BASIC_STACK_SIZE;
if (goodsize > LUAI_MAXSTACK)
goodsize = LUAI_MAXSTACK; /* respect stack limit */
/* if thread is currently not handling a stack overflow and its
good size is smaller than current size, shrink its stack */
- if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) &&
- goodsize < L->stacksize)
+ if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) && goodsize < L->stacksize)
luaD_reallocstack(L, goodsize, 0); /* ok if that fails */
else /* don't change stack */
condmovestack(L,{},{}); /* (change only for debugging) */
Source: GitHub Lua Commit 6298903
GC and stack reallocation ordering fix in ldo.c:
f = fvalue(s2v(func));
Cfunc: {
int n; /* number of returns */
- CallInfo *ci = next_ci(L);
- checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
+ CallInfo *ci;
+ checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
+ L->ci = ci = next_ci(L);
ci->nresults = nresults;
ci->callstatus = CIST_C;
ci->top = L->top + LUA_MINSTACK;
ci->func = func;
- L->ci = ci;
lua_assert(ci->top <= L->stack_last);
if (L->hookmask & LUA_MASKCALL) {
int narg = cast_int(L->top - func) - 1;
Source: GitHub Lua Commit eb41999
Detection Methods for CVE-2020-15888
Indicators of Compromise
- Unexpected crashes or segmentation faults in applications using Lua scripting
- Memory corruption errors in system logs associated with Lua interpreter processes
- Abnormal memory usage patterns in Lua-embedded applications
- Core dumps showing heap corruption in Lua-related memory regions
Detection Strategies
- Monitor application logs for Lua interpreter crashes with stack-related error messages
- Implement runtime memory sanitizers (AddressSanitizer, Valgrind) during testing to detect heap corruption
- Deploy SentinelOne Singularity to detect anomalous memory access patterns indicative of exploitation
- Audit systems for Lua versions prior to the security patches
Monitoring Recommendations
- Enable verbose logging for applications that execute Lua scripts from external sources
- Implement process monitoring for Lua interpreter child processes with unusual behavior
- Configure alerting for repeated crashes in Lua-embedded applications
- Monitor network traffic for potential delivery of malicious Lua scripts to vulnerable endpoints
How to Mitigate CVE-2020-15888
Immediate Actions Required
- Update Lua to a version containing the security patches (commits 6298903 and eb41999)
- Restrict execution of untrusted Lua scripts until patching is complete
- Audit applications embedding Lua to identify all vulnerable deployments
- Consider sandboxing Lua execution environments with restricted capabilities
Patch Information
The Lua development team has released patches addressing this vulnerability. The fixes are available in the official Lua GitHub repository:
- Commit 6298903: Maintains minimum stack size during shrink operations by using BASIC_STACK_SIZE instead of a percentage-based calculation
- Commit eb41999: Reorders CallInfo creation and stack checking to ensure GC-safe operation, introducing the checkstackGCp macro
Organizations should update to Lua versions that include these patches or manually apply the commits to their Lua source builds.
Workarounds
- Disable or limit execution of Lua scripts from untrusted sources
- Implement input validation and sanitization for Lua code before execution
- Deploy application-level sandboxing to contain potential exploitation attempts
- Configure memory limits for Lua interpreters to reduce exploitation impact
# Example: Checking Lua version and updating on Debian/Ubuntu
lua -v
sudo apt-get update && sudo apt-get install --only-upgrade lua5.4
# For source builds, apply patches manually
cd lua-source-directory
git fetch origin
git cherry-pick 6298903e35217ab69c279056f925fb72900ce0b7
git cherry-pick eb41999461b6f428186c55abd95f4ce1a76217d5
make clean && make linux
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

