Langroid has WAF Bypass Leading to RCE in TableChatAgent
Description
Langroid is a framework for building large-language-model-powered applications. Prior to version 0.59.32, there is a bypass to the fix for CVE-2025-46724. TableChatAgent can call pandas_eval tool to evaluate the expression. There is a WAF in langroid/utils/pandas_utils.py introduced to block code injection CVE-2025-46724. However it can be bypassed due to _literal_ok() returning False instead of raising UnsafeCommandError on invalid input, combined with unrestricted access to dangerous dunder attributes (__init__, __globals__, __builtins__). This allows chaining whitelisted DataFrame methods to leak the eval builtin and execute arbitrary code. This issue has been patched in version 0.59.32.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
langroidPyPI | < 0.59.32 | 0.59.32 |
Affected products
1Patches
130abbc1a854dFix CVE-2025-46724 bypass in TableChatAgent sanitization (#966)
2 files changed · +34 −0
langroid/utils/pandas_utils.py+11 −0 modified@@ -237,6 +237,16 @@ def visit_Subscript(self, node: ast.Subscript) -> None: raise UnsafeCommandError("subscript must be literal") self.generic_visit(node) + # Attribute access + def visit_Attribute(self, node: ast.Attribute) -> None: + # Block dunder attributes to prevent access to __init__, __globals__, etc. + if node.attr.startswith("__") and node.attr.endswith("__"): + raise UnsafeCommandError(f"dunder attribute '{node.attr}' not allowed") + # Block single underscore private attributes as well for defense in depth + if node.attr.startswith("_") and node.attr not in WHITELISTED_DF_METHODS: + raise UnsafeCommandError(f"private attribute '{node.attr}' not allowed") + self.generic_visit(node) + # Method calls def visit_Call(self, node: ast.Call) -> None: if not isinstance(node.func, ast.Attribute): @@ -253,6 +263,7 @@ def visit_Call(self, node: ast.Call) -> None: for kw in node.keywords: if kw.arg in BLOCKED_KW: raise UnsafeCommandError(f"kwarg '{kw.arg}' is blocked") + # Check numeric limits on literals; non-literals validated via generic_visit _literal_ok(kw.value) for arg in node.args: _literal_ok(arg)
tests/main/test_pandas_utils.py+23 −0 modified@@ -40,6 +40,29 @@ r"unexpected variable 'other_var'", ), (DEEP_EXPR, r"AST nesting too deep"), + # CVE-2025-46724 bypass tests - dunder attribute access + ("df.__init__", r"dunder attribute '__init__' not allowed"), + ("df.__class__", r"dunder attribute '__class__' not allowed"), + ("df.__globals__", r"dunder attribute '__globals__' not allowed"), + ("df.__builtins__", r"dunder attribute '__builtins__' not allowed"), + # CVE-2025-46724 bypass tests - private attribute access + ("df._private", r"private attribute '_private' not allowed"), + ("df._internal_method()", r"method '_internal_method' not permitted"), + # CVE-2025-46724 bypass tests - dunder access via kwargs (the actual bypass vector) + ( + "df.groupby(by=df.__init__)", + r"dunder attribute '__init__' not allowed", + ), + ( + "df.groupby(by=df.__class__.__bases__)", + r"dunder attribute '__.+__' not allowed", + ), + # Full PoC exploit payload - blocks on dunder attribute access + ( + "df.add_prefix(\"__import__('os').system('ls')#\").T.groupby(" + "by=df.__init__.__globals__['__builtins__']['eval'])", + r"dunder attribute '__.+__' not allowed", + ), ]
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-x34r-63hx-w57fghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-25481ghsaADVISORY
- github.com/langroid/langroid/commit/30abbc1a854dee22fbd2f8b2f575dfdabdb603eaghsax_refsource_MISCWEB
- github.com/langroid/langroid/security/advisories/GHSA-jqq5-wc57-f8hjghsax_refsource_MISCWEB
- github.com/langroid/langroid/security/advisories/GHSA-x34r-63hx-w57fghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.