---
When you play with a programming language as widely used as Lua, strange little bugs can have big consequences. That’s the case for CVE-2022-28805, a security issue found in Lua versions 5.4. up to (but not including) 5.4.4. Most folks running Lua just fine don’t need to panic. But if you're compiling or running untrusted Lua code, this bug is worth your attention.
Let's break down what happened, why it matters, show some code, and provide details for researchers or defenders.
What's the Bug?
Lua, by design, is an *embeddable* scripting language—favorite of game developers, embedded projects, and sysadmins everywhere. The bug in question lives inside lparser.c, a core part of how Lua reads and compiles scripts.
A function called singlevar() was missing a crucial call to luaK_exp2anyregup(). The omission causes a heap-based buffer over-read under certain edge circumstances. An attacker could exploit this if they can get your Lua interpreter to compile their own (malicious) code.
More details here:
- NIST CVE Details
- Lua's Own Changelog (5.4.4)
Here’s the relevant portion of lparser.c before it was fixed, simplified for clarity
static void singlevar (LexState *ls, expdesc *var) {
TString *varname = str_checkname(ls);
FuncState *fs = ls->fs;
if (singlevaraux(fs, varname, var, 1) == VVOID) {
luaK_semerror(ls, "undefined variable", varname);
}
// Missing: luaK_exp2anyregup(fs, var);
}
It *should have* had a call like
luaK_exp2anyregup(fs, var);
This call ensures a variable’s value is properly moved to a register or upvalue as needed before further use. Without it, an attacker can craft code that tricks the parser into reading from outside a valid memory region—potentially leaking data or causing a crash.
The Exploit: How Could It Work?
Researcher Zhaofeng Zhang reported the bug after noticing that singlevar may leave an expdesc in an unexpected state.
One path to triggering this involves complex scoping, upvalues (which allow closures to reference variables from outer functions), and malicious script construction. Here’s a minimal illustration (do not use except for education):
-- Tricky Lua code designed to hit the bug in older Lua 5.4.x
local function outer()
local a
return function()
-- Force compiler to process 'a' through singlevar
return a
end
end
By carefully stacking up values and control flows, an attacker can bait the parser into reading past the end of an allocated memory area.
In C Terms
Imagine a buffer is allocated for N variables, but the code lets you access N+1. That’s bad news.
How to Fix
Upgrade! The Lua team patched this in version 5.4.4. If your app builds or ships Lua, upgrade as soon as feasible.
Alternatively, apply the official patch:
@@
-static void singlevar (LexState *ls, expdesc *var) {
+static void singlevar (LexState *ls, expdesc *var) {
TString *varname = str_checkname(ls);
FuncState *fs = ls->fs;
if (singlevaraux(fs, varname, var, 1) == VVOID) {
luaK_semerror(ls, "undefined variable", varname);
}
+ luaK_exp2anyregup(fs, var);
}
Should You Worry?
If you control *all* the Lua scripts in your application, you’re probably safe. If you run user-supplied code (think game mods, sandboxes, or online platforms), patch right away.
References
- Official Lua Bug Report
- CVE-2022-28805 at NIST
- Lua 5.4.4 Download
- GitHub Commit Fix
Conclusion
CVE-2022-28805 is another reason to keep even tiny, “safe” languages up to date. Bugs in compilers can open surprising security holes, especially when running code you didn’t write. Always update, audit, and sandbox when running untrusted code—no matter the language.
If you want to dive deeper or test, check out the official Lua source and changelog. Safe coding!
Timeline
Published on: 04/08/2022 06:15:00 UTC
Last modified on: 08/04/2022 04:15:00 UTC