CVE-2026-7466
AgentFlow allows RCE of local Python files via a crafted `pipeline_path`.
- CVSS 7.7
- CWE-94
- Input Validation and Sanitization
- Local
AgentFlow contains an arbitrary code execution vulnerability that allows attackers to execute local Python pipeline files by supplying a user-controlled pipeline_path parameter to the POST /api/runs and POST /api/runs/validate endpoints. Attackers can induce requests to the local AgentFlow API to load and execute existing Python pipeline files on disk, resulting in code execution in the context of the user running AgentFlow.
- CWE
- CWE-94
- CVSS base score
- 7.7
- Published
- 2026-04-29
- OWASP
- A08 Software and Data Integrity Failures
- Orthogonal defect classification
- Checking
- Code defect classification
- Missing Check
- Category
- Input Validation and Sanitization
- Subcategory
- Local File Inclusion (LFI)
- Accessibility scope
- Local
- Impact
- Arbitrary Code Execution
- Affected component
- AgentFlow
- Fixed by upgrading
- Yes
Solution
Upgrade AgentFlow to version 0.2.2 or later.
Vulnerable code sample
from flask import Flask, request, jsonify
app = Flask(__name__)
def execute_pipeline_from_path(file_path):
"""
Loads a Python file from the given path and executes its content.
This is the core of the vulnerability.
"""
with open(file_path, 'r') as f:
pipeline_code = f.read()
# The vulnerability: executing code from a user-controlled file path.
# An attacker could supply a path to any Python file on the server.
exec(pipeline_code, globals())
@app.route('/api/runs', methods=['POST'])
def create_run():
"""
Vulnerable endpoint that takes a 'pipeline_path' and executes it.
"""
data = request.get_json()
if not data or 'pipeline_path' not in data:
return jsonify({"error": "pipeline_path is required"}), 400
pipeline_path = data['pipeline_path']
try:
# No validation or sanitization is performed on the pipeline_path.
execute_pipeline_from_path(pipeline_path)
return jsonify({"status": "success", "message": f"Pipeline from {pipeline_path} executed."})
except FileNotFoundError:
return jsonify({"error": f"File not found: {pipeline_path}"}), 404
except Exception as e:
return jsonify({"error": f"An error occurred: {str(e)}"}), 500
@app.route('/api/runs/validate', methods=['POST'])
def validate_run():
"""
Another vulnerable endpoint that also executes code from 'pipeline_path'.
"""
data = request.get_json()
if not data or 'pipeline_path' not in data:
return jsonify({"error": "pipeline_path is required"}), 400
pipeline_path = data['pipeline_path']
try:
# The same vulnerability exists here.
execute_pipeline_from_path(pipeline_path)
return jsonify({"status": "valid", "message": f"Pipeline from {pipeline_path} is valid and was test-executed."})
except FileNotFoundError:
return jsonify({"error": f"File not found: {pipeline_path}"}), 404
except Exception as e:
return jsonify({"error": f"An error occurred during validation: {str(e)}"}), 500
if __name__ == '__main__':
# To test this vulnerability:
# 1. Save a python file, e.g., /tmp/malicious_pipeline.py with content: print("Code executed from malicious file!")
# 2. Run this Flask application.
# 3. Send a POST request:
# curl -X POST -H "Content-Type: application/json" -d '{"pipeline_path": "/tmp/malicious_pipeline.py"}' http://127.0.0.1:5000/api/runs
app.run(debug=True)Patched code sample
import os
from flask import Flask, request, jsonify
# --- The Fix ---
# A predefined, secure base directory where all legitimate pipelines are stored.
# os.path.abspath ensures we have a canonical base path to compare against.
SAFE_PIPELINE_DIRECTORY = os.path.abspath('./allowed_pipelines')
# --- End of Fix ---
# Create the directory if it doesn't exist for the example to run
if not os.path.exists(SAFE_PIPELINE_DIRECTORY):
os.makedirs(SAFE_PIPELINE_DIRECTORY)
# Create a dummy pipeline file for a valid test case
with open(os.path.join(SAFE_PIPELINE_DIRECTORY, 'legit_pipeline.py'), 'w') as f:
f.write('print("Executing the legitimate pipeline.")\n')
app = Flask(__name__)
@app.route('/api/runs', methods=['POST'])
def run_pipeline():
data = request.get_json()
if not data or 'pipeline_path' not in data:
return jsonify({"error": "pipeline_path is required"}), 400
pipeline_path = data['pipeline_path']
# --- The Fix ---
# 1. Safely join the trusted base directory with the user-provided path.
# This prevents the user path from being treated as an absolute path.
requested_path = os.path.join(SAFE_PIPELINE_DIRECTORY, pipeline_path)
# 2. Resolve the real, absolute path (e.g., handles '..', symlinks).
absolute_path = os.path.abspath(requested_path)
# 3. CRITICAL CHECK: Ensure the resolved absolute path is still inside
# the safe base directory. If not, it's a path traversal attempt.
if not absolute_path.startswith(SAFE_PIPELINE_DIRECTORY):
return jsonify({"error": "Path traversal attempt detected"}), 403
# --- End of Fix ---
if not os.path.isfile(absolute_path):
return jsonify({"error": "Pipeline file not found"}), 404
try:
# In a real application, this would use a secure method to execute
# the pipeline. For this example, we simulate execution.
print(f"--- SIMULATING EXECUTION OF: {absolute_path} ---")
with open(absolute_path, 'r') as f:
code = f.read()
# In a real scenario, this might be exec(), importlib, or a subprocess
# call. The security lies in the path validation above.
exec(code)
print("--- SIMULATION COMPLETE ---")
return jsonify({"status": "success", "executed_pipeline": absolute_path}), 200
except Exception as e:
return jsonify({"error": f"Failed to execute pipeline: {str(e)}"}), 500
if __name__ == '__main__':
print(f"Allowed pipelines must be in: {SAFE_PIPELINE_DIRECTORY}")
print("Example valid request:")
print("curl -X POST -H \"Content-Type: application/json\" -d '{\"pipeline_path\": \"legit_pipeline.py\"}' http://127.0.0.1:5000/api/runs")
print("Example invalid (path traversal) request:")
print("curl -X POST -H \"Content-Type: application/json\" -d '{\"pipeline_path\": \"../../../../etc/passwd\"}' http://127.0.0.1:5000/api/runs")
app.run(port=5000)Payload
{
"pipeline_path": "/tmp/malicious_pipeline.py"
}
Cite this entry
@misc{vaitp:cve20267466,
title = {{AgentFlow allows RCE of local Python files via a crafted `pipeline_path`.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-7466},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-7466/}}
}
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 ::
