Task/step output handlers run eval() on raw model output (code execution via model reply)
⚠️ Check for existing issues before proceeding. ⚠️
- I have searched the existing issues, and there is no existing issue for my problem
Where are you using SuperAGI?
MacOS
Which branch of SuperAGI are you using?
Main
Do you use OpenAI GPT-3.5 or GPT-4?
GPT-4
Which area covers your issue best?
Agents
Describe your issue.
The task/step output handlers in the agent loop pass the raw model reply to Python's built-in eval(). Because the model reply is attacker-influenceable text (prompt injection, a compromised/malicious model endpoint, or an untrusted tool result that ends up echoed back into the completion), an array-shaped reply that contains a Python expression is evaluated as code and runs in the backend process rather than being parsed as data.
This is a defense-in-depth / fail-safe-default problem: model output should be treated as untrusted data and parsed with a literal-only parser, never executed. The handlers today treat it as trusted code.
Decisive sinks (current main):
TaskOutputHandler.handle()—superagi/agent/output_handler.py(theoutput_type='tasks'branch). The reply is run through the cosmeticJsonCleaner.extract_json_array_section()and then passed toeval().ReplaceTaskOutputHandler.handle()—superagi/agent/output_handler.py(theoutput_type='replace_tasks'branch). Sameextract_json_array_section()+eval()pattern.QueueStepHandler._process_reply()—superagi/agent/queue_step_handler.py(np.array(eval(assistant_reply))...on theTASK_QUEUEtool step).
Root cause is shared: JsonCleaner.extract_json_array_section() in superagi/helper/json_cleaner.py only slices the substring between the first [ and the last ]; it performs no content validation, so whatever is inside the brackets flows straight into eval().
All three call-sites are reachable on default-seeded workflows (the Dynamic Task Queue iteration workflow for the two output handlers, and the built-in Sales Engagement / Recruitment workflows for the queue step handler), so no non-default configuration is required.
Impact (conservative): evaluating untrusted model output as Python can lead to unintended code execution in the backend process under attacker-influenced model replies. I'm deliberately not including a weaponized payload here.
Expected behaviour: the handlers should parse the reply as a literal list of task strings and reject anything that is not a literal list, without ever executing it. A natural fix is to replace eval() with a literal-only parser such as ast.literal_eval (stdlib only) behind a small shared helper, returning a list for a literal array and raising on non-literal input. ast.literal_eval accepts both single-quoted (str(dict)-style, as OpenAI emits) and double-quoted (JSON-style) arrays, so legitimate replies parse exactly as before while embedded calls/imports can never run.
I've prepared a fix and can open a PR.
How to replicate your Issue?
This is reachable on default-seeded workflows (e.g. the Dynamic Task Queue iteration workflow, which drives the two output handlers, and the built-in Sales Engagement / Recruitment workflows, which drive the queue step handler). When the configured model returns an array-shaped reply for one of these steps, the bracketed contents of the reply are evaluated by eval() instead of being parsed as data. Any agent whose run reaches a task-queue / replace-task / TASK_QUEUE step and whose model reply contains a Python expression inside the array brackets will exercise the affected path.
I have a minimal, fully-mocked regression test (no network / no live model) that demonstrates the affected handlers executing an embedded expression on the current main and being safely rejected after the proposed fix; I can include it with the PR rather than posting an executable payload here.
Upload Error Log Content
Not applicable — this is a code-level issue identified by reading the handler call-sites on main, not a crash, so there is no error/stack-trace log to attach. The relevant locations are superagi/agent/output_handler.py (TaskOutputHandler.handle / ReplaceTaskOutputHandler.handle) and superagi/agent/queue_step_handler.py (QueueStepHandler._process_reply), all sharing superagi/helper/json_cleaner.py::extract_json_array_section.
Source: TransformerOptimus/SuperAGI