October 2, 2024·6 min read·engineeringvalkeysecurityluavalidation

Valkey patches Lua conversion and input-validation defects

Valkey 8.0.1 and 7.2.7 carry security fixes for Lua, ACL selectors and pattern matching. The source changes show distinct failure mechanisms behind the release's security urgency.

An input can be valid at one layer and still exceed assumptions inside a helper it invokes. Valkey's October security release addresses several such boundaries. Valkey 8.0.1, published on October 2, fixes problems involving Lua library operations, malformed ACL selectors and unbounded pattern matching. The release recommends applying the security fixes as soon as possible.

The 8.0.1 release notes identify CVE-2024-31449 as a Lua stack-overflow and potential remote-code-execution problem. They identify CVE-2024-31227 and CVE-2024-31228 as potential denial-of-service problems involving ACL selectors and pattern matching respectively. These are separate mechanisms. Treating them as one generic scripting vulnerability would obscure both the affected code and the corrections.

I favour Valkey where the Redis model is useful, and I have used the underlying technology since its release. That familiarity makes these internal boundaries worth understanding. A database with a compact command interface still contains interpreters and parsers whose implementation limits matter to the process serving every client.

The maintenance branch receives the fixes too

The 7.2.7 notes list the same security identifiers and recommend applying the fixes. That gives users of the earlier stable line a corresponding patched release. Adopting the new major version's performance mechanisms is therefore a separate decision from obtaining these security corrections.

The distinction matters operationally because the purpose of a security patch is to correct the vulnerable implementation in the deployed line. A deployment does not need to adopt every new feature to benefit from the maintenance branch's correction. Conversely, remaining on a maintenance line does not remove the need to consume its security updates.

The version-pinned notes are the basis for those release claims. The source difference from 8.0.0 to 8.0.1 supplies more detail about what changed. It makes the patch inspectable without relying on assumptions about how an attack might be constructed against a particular deployment.

A signed integer boundary affects Lua formatting

The Lua change is in the bit library's hexadecimal conversion function. That code uses a fixed-size output buffer and a requested digit count. A negative count selects uppercase output after the code negates the count, and a later bound limits the digit count to the buffer's capacity.

Negating the smallest signed integer is a special case because its positive counterpart is outside the same signed integer range. The new guard handles INT32_MIN before the negation. The following lines show the relevant ordering in the release patch.

if (n == INT32_MIN) n = INT32_MIN+1;
if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
if (n > 8) n = 8;

The order matters because an upper bound applied after an invalid arithmetic transformation does not establish the property the later loop assumes. The guard moves the extreme input away from the unrepresentable negation before the code converts the sign and limits the output width. This is a small correction at the input-to-formatting boundary.

The source gives a more concrete explanation than the broad phrase Lua stack overflow. A script reaches a library function implemented in C, and that function's arithmetic influences how it fills a stack-allocated buffer. Correctness depends on handling the full input range before the loop uses the resulting value.

This does not justify inventing an exploit sequence or claiming that every script user can obtain code execution in every environment. The release notes state the potential consequence, and the patch shows the integer-boundary correction. Those are sufficient facts to explain why the issue needs a server update without adding unsupported details about exploitation.

ACL syntax must establish a meaningful permission

The ACL parser in 8.0.1 handles key-pattern rules with permission qualifiers. In the relevant branch, it collects read and write permission flags before accepting the separator that introduces the pattern. The patch requires those flags to be nonzero when it accepts that separator.

Before the change, the separator could be accepted without establishing a read or write permission. The corrected condition rejects that form through the parser's invalid-input path. This is distinct from deciding whether a client has a particular permission. It concerns constructing an internally meaningful rule in the first place.

The patch adds a regression test for a selector missing those permission qualifiers. The expected result is a syntax error from ACL SETUSER. This checks rejection at construction, before the malformed selector can become policy consulted by later operations.

After parsing, the code creates a key-pattern object with the collected flags. The new precondition therefore protects the representation later code consumes. A parser that accepts malformed syntax can create an invalid internal object even if ordinary rules work correctly. The release's denial-of-service description concerns that kind of failure boundary.

Permission configuration deserves the same input discipline as data commands. A rule is executable policy in the sense that other operations consult its result, and invalid policy state can affect the server beyond the command that introduced it. Rejecting the malformed form keeps the failure at parsing, where the operation can return an error.

I find the distinction useful when interpreting ACL-related fixes. Authentication and authorization describe who may ask for an operation. Input validation describes whether the requested rule has a valid internal meaning. The latter remains necessary even for a command whose callers already pass permission checks.

Pattern matching receives an explicit recursion bound

The pattern matcher implements glob-style matching. Its wildcard branch can recursively try the rest of a pattern against candidate positions in the input string. That recursion consumes execution resources even though the pattern itself is just a string supplied to a higher-level operation.

The patch introduces a nesting argument to the internal matcher. The public wrapper starts the count at zero, and recursive calls increment it. When nesting exceeds 1000, the function returns no match. That is the actual boundary added by this version.

The limit concerns recursive depth, not simply the total length of every accepted pattern. It also does not establish a universal runtime bound for every use of matching. The concrete change prevents this recursive path from continuing beyond its stated depth. Describing that mechanism directly is more accurate than saying arbitrary pattern processing has become constant time.

The matcher already contains logic to skip longer candidates after certain failed matches. The new depth check adds another protection without replacing the matching algorithm. Existing optimization and an explicit resource limit solve different problems. An algorithm can avoid some redundant work while still needing a boundary on the stack it may consume.

The internal matcher also receives the remaining pattern and string lengths explicitly. Its recursive wildcard call advances through those inputs and increments the new nesting count. The added limit is therefore associated with the recursive search state, while the ordinary wrapper retains the public calling shape. Callers do not need another argument to obtain the protection because the wrapper initializes the count itself.

This placement matters for shared helper code. Adding a check only to one command that accepts a pattern would leave other users of the matcher dependent on their own checks. Establishing the bound inside the recursive implementation applies it wherever that wrapper reaches the same code. The source's no-match return also preserves the helper's ordinary result type, so the protected path terminates as a failed match instead of introducing another result representation for every caller to interpret.

The release also corrects contextual cluster calls

Outside the security list, 8.0.1 fixes cluster topology commands invoked from a script or module. The notes identify both crashes and incorrect TCP or TLS port information in those contexts. These are separate from the pattern and ACL defects, but they reinforce that a command's calling context can matter to its implementation.

The release also corrects the default Sentinel configuration and build issues for certain environments. Those changes affect whether the packaged server can start or build as intended. They do not weaken the security urgency attached to the three named vulnerabilities.

For users on either stable line, the release records identify an available patch containing the security work. The source shows an extreme-integer guard, a stronger ACL parsing precondition and a recursion limit. Each correction establishes a boundary before later code consumes the resulting value or object, which is the practical mechanism behind this update.