Out-of-Bounds Read in kname() via Unchecked Constant Table Index

70 views
Skip to first unread message

Biniam Fisseha Demissie

unread,
Jan 12, 2026, 6:06:34 PM (9 days ago) Jan 12
to lua-l
Hi all,

A verified out-of-bounds read vulnerability exists in the kname() function within `ldebug.c`.

Affected versions: 5.4.8 (while the PoC is for v5.4.8 on a MacOS, the bug is also tested on 5.3.4 with a different PoC on a downstream project)
Vulnerability Type: oob_read
File: ldebug.c
Affected Code:
  static const char *kname (const Proto *p, int index, const char **name) {
    TValue *kvalue = &p->k[index];              // <-- SINK
    if (ttisstring(kvalue)) {
      *name = getstr(tsvalue(kvalue));
      return "constant";
    }
    else {
      *name = "?";
      return NULL;
    }
  }

Root cause:
The function assumes that `index` is a valid, non-negative index within the bounds of the constant table `p->k`. There are:
- No checks for `index < 0`
- No checks for `index >= p->sizek` (or equivalent size field)
- No validation that `p` or `p->k` is non-NULL

As a result, pointer arithmetic on `p->k[index]` may compute an address outside the allocated array.

Scenario:
- Craft malformed Lua bytecode chunk with manipulated instruction operands that decode into invalid constant index.During execution, particularily in debug, error-reporting or symbol resolution paths, the vm invokes kname() to get a constant's name.

Because kname() blindly dereferences `p->k[index]`, a maliciously chosen `index` (negative or excessively large) causes the vm to read memory outside the constant table. Depending on memory layout this could:
- leak adjacent heap
- segfault (DoS)

PoC:
a malformed Lua bytecode, when run (lua exploit54_patched.luac) makes kname() read invalid memory when trying to format error message (instead of reading constant string 'undefined_var', it tries to read garbage from p->k[255]).

Example patch:
static const char *kname (const Proto *p, int index, const char **name) {
  if (p == NULL || p->k == NULL || index < 0 || index >= p->sizek) {
    *name = "?";
    return NULL;
  }

  TValue *kvalue = &p->k[index];
  if (ttisstring(kvalue)) {
    *name = getstr(tsvalue(kvalue));
    return "constant";
  }
  else {
    *name = "?";
    return NULL;
  }
}

Regards,
Biniam
exploit54_patched.luac

Xmilia Hermit

unread,
Jan 12, 2026, 6:13:50 PM (9 days ago) Jan 12
to lu...@googlegroups.com
Fisseha Demissie:
> PoC:
> a malformed Lua bytecode, when run (lua exploit54_patched.luac) makes
> kname() read invalid memory when trying to format error message (instead
> of reading constant string 'undefined_var', it tries to read garbage
> from p->k[255]).

From the manual:
Lua does not check the consistency of binary chunks. Maliciously crafted
binary chunks can crash the interpreter.

Can this also be reproduced using non-binary chunks?

Regards,
Xmilia

Biniam Fisseha Demissie

unread,
Jan 12, 2026, 6:26:39 PM (9 days ago) Jan 12
to lua-l
> Can this also be reproduced using non-binary chunks?

Unlikely. Only affects applications that load untrusted precompiled bytecode.

Regards,
Biniam
Reply all
Reply to author
Forward
0 new messages