Command Injection in run-llama/llama_index
Description
A command injection vulnerability exists in the run-llama/llama_index repository, specifically within the safe_eval function. Attackers can bypass the intended security mechanism, which checks for the presence of underscores in code generated by LLM, to execute arbitrary code. This is achieved by crafting input that does not contain an underscore but still results in the execution of OS commands. The vulnerability allows for remote code execution (RCE) on the server hosting the application.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
CVE-2024-3271 is a command injection flaw in LlamaIndex's safe_eval function, allowing remote code execution by bypassing underscore checks in LLM-generated code.
A command injection vulnerability exists in the safe_eval function of the run-llama/llama_index repository. The root cause is an insufficient security mechanism that only checks for underscores in LLM-generated code before evaluation. An attacker can craft input that avoids underscores but still executes arbitrary OS commands, bypassing the intended restriction [1].
Exploitation does not require authentication if the vulnerable endpoint is exposed. The attacker can provide crafted input to the LLM or directly to the component that calls safe_eval, such as the PandasQueryEngine. The bypass is achieved by using built-in functions or attribute accesses that do not contain underscores but are not in the allowlist of safe builtins. References show that the original code only checked for private entity access (starting with '_'), but later patches added checks for disallowed builtins and import modules to strengthen the protection [3][4].
The impact is remote code execution (RCE) on the server hosting the application, allowing full compromise of the system [1].
Mitigation is available via commits that restrict allowed builtins and block imports in the safe_eval function [3][4]. Users should update to a version containing these patches. There is no indication that the vulnerability is currently listed in CISA's KEV.
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
llama-index-corePyPI | < 0.10.24 | 0.10.24 |
Affected products
2- run-llama/run-llama/llama_indexv5Range: unspecified
Patches
35fbcb5a8b9f2stricter access to builting in pandas query engine
1 file changed · +11 −7
llama-index-core/llama_index/core/exec_utils.py+11 −7 modified@@ -45,20 +45,16 @@ def _restricted_import( "float": float, "format": format, "frozenset": frozenset, - "getattr": getattr, - "hasattr": hasattr, "hash": hash, "hex": hex, "int": int, "isinstance": isinstance, "issubclass": issubclass, - "iter": iter, "len": len, "list": list, "map": map, "max": max, "min": min, - "next": next, "oct": oct, "ord": ord, "pow": pow, @@ -68,7 +64,6 @@ def _restricted_import( "reversed": reversed, "round": round, "set": set, - "setattr": setattr, "slice": slice, "sorted": sorted, "str": str, @@ -94,23 +89,31 @@ def _get_restricted_globals(__globals: Union[dict, None]) -> Any: class DunderVisitor(ast.NodeVisitor): def __init__(self) -> None: self.has_access_to_private_entity = False + self.has_access_to_disallowed_builtin = False def visit_Name(self, node: ast.Name) -> None: if node.id.startswith("_"): self.has_access_to_private_entity = True + if node.id not in ALLOWED_BUILTINS: + self.has_access_to_disallowed_builtin = True self.generic_visit(node) def visit_Attribute(self, node: ast.Attribute) -> None: if node.attr.startswith("_"): self.has_access_to_private_entity = True + if node.attr not in ALLOWED_BUILTINS: + self.has_access_to_disallowed_builtin = True self.generic_visit(node) def _contains_protected_access(code: str) -> bool: tree = ast.parse(code) dunder_visitor = DunderVisitor() dunder_visitor.visit(tree) - return dunder_visitor.has_access_to_private_entity + return ( + dunder_visitor.has_access_to_private_entity + or dunder_visitor.has_access_to_disallowed_builtin + ) def _verify_source_safety(__source: Union[str, bytes, CodeType]) -> None: @@ -124,7 +127,8 @@ def _verify_source_safety(__source: Union[str, bytes, CodeType]) -> None: __source = __source.decode() if _contains_protected_access(__source): raise RuntimeError( - "Execution of code containing references to private or dunder methods is forbidden!" + "Execution of code containing references to private or dunder methods, " + "or disallowed builtins, is forbidden!" )
8a83240087642c92e88838a5stricter access to builting in pandas query engine (#12278)
2 files changed · +27 −10
llama-index-core/llama_index/core/exec_utils.py+25 −7 modified@@ -45,20 +45,16 @@ def _restricted_import( "float": float, "format": format, "frozenset": frozenset, - "getattr": getattr, - "hasattr": hasattr, "hash": hash, "hex": hex, "int": int, "isinstance": isinstance, "issubclass": issubclass, - "iter": iter, "len": len, "list": list, "map": map, "max": max, "min": min, - "next": next, "oct": oct, "ord": ord, "pow": pow, @@ -68,7 +64,6 @@ def _restricted_import( "reversed": reversed, "round": round, "set": set, - "setattr": setattr, "slice": slice, "sorted": sorted, "str": str, @@ -94,23 +89,45 @@ def _get_restricted_globals(__globals: Union[dict, None]) -> Any: class DunderVisitor(ast.NodeVisitor): def __init__(self) -> None: self.has_access_to_private_entity = False + self.has_access_to_disallowed_builtin = False + + builtins = globals()["__builtins__"].keys() + self._builtins = builtins def visit_Name(self, node: ast.Name) -> None: if node.id.startswith("_"): self.has_access_to_private_entity = True + if node.id not in ALLOWED_BUILTINS and node.id in self._builtins: + self.has_access_to_disallowed_builtin = True self.generic_visit(node) def visit_Attribute(self, node: ast.Attribute) -> None: if node.attr.startswith("_"): self.has_access_to_private_entity = True + if node.attr not in ALLOWED_BUILTINS and node.attr in self._builtins: + self.has_access_to_disallowed_builtin = True self.generic_visit(node) def _contains_protected_access(code: str) -> bool: + # do not allow imports + imports_modules = False tree = ast.parse(code) + for node in ast.iter_child_nodes(tree): + if isinstance(node, ast.Import): + imports_modules = True + elif isinstance(node, ast.ImportFrom): + imports_modules = True + else: + continue + dunder_visitor = DunderVisitor() dunder_visitor.visit(tree) - return dunder_visitor.has_access_to_private_entity + return ( + dunder_visitor.has_access_to_private_entity + or dunder_visitor.has_access_to_disallowed_builtin + or imports_modules + ) def _verify_source_safety(__source: Union[str, bytes, CodeType]) -> None: @@ -124,7 +141,8 @@ def _verify_source_safety(__source: Union[str, bytes, CodeType]) -> None: __source = __source.decode() if _contains_protected_access(__source): raise RuntimeError( - "Execution of code containing references to private or dunder methods is forbidden!" + "Execution of code containing references to private or dunder methods, " + "disallowed builtins, or any imports, is forbidden!" )
llama-index-core/tests/query_engine/test_pandas.py+2 −3 modified@@ -111,8 +111,7 @@ def test_default_output_processor_rce2() -> None: output = parser.parse(injected_code) assert ( - "Execution of code containing references to private or dunder methods is forbidden!" - in output + "Execution of code containing references to private or dunder methods" in output ), "Injected code executed successfully!" @@ -152,7 +151,7 @@ def test_default_output_processor_e2e(tmp_path: Path) -> None: assert isinstance(response, Response) # raw df should be equal to slice of dataframe that's just population at location 2 rmetadata = cast(Dict[str, Any], response.metadata) - assert rmetadata["raw_pandas_output"] == str(df["population"].iloc[2:3]) + assert rmetadata["raw_pandas_output"] == str(df["population"].iloc[2]) # attack 1: fail! print("[+] Attack 1 starts, it should fail!")
Vulnerability mechanics
Generated 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-r6gp-rff2-p3hfghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-3271ghsaADVISORY
- github.com/run-llama/llama_index/commit/2c92e88838a5f481d50840240b1dd3180066c6f5ghsaWEB
- github.com/run-llama/llama_index/commit/5fbcb5a8b9f20f81b791c7fc8849e352613ab475ghsaWEB
- huntr.com/bounties/9b32490e-7cf9-470e-8d49-ba083ae7a279ghsaWEB
News mentions
0No linked articles in our index yet.