fix: Replace unsafe `ast.literal_eval` with `extract_json` in `parse_tool_call` (#105)

Remove the potential DoS and code-execution vulnerability by replacing `ast.literal_eval(tool_call)` with `json.loads` and `extract_json` in `cli/main.py`. Ensures strict JSON parsing without breaking tests or relying on unsafe structures.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: aguzererler <6199053+aguzererler@users.noreply.github.com>
This commit is contained in:
ahmet guzererler 2026-03-25 10:17:28 +01:00 committed by GitHub
parent c39dcc6fe8
commit b1a775882e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 10 additions and 3 deletions

View File

@ -977,7 +977,7 @@ def parse_tool_call(tool_call) -> tuple[str, dict | str]:
"""Parse a tool call into a name and arguments dictionary.
Handles dicts, objects with name/args attributes, and string representations.
"""
import ast
import json
if isinstance(tool_call, dict):
tool_name = tool_call.get("name", "Unknown Tool")
@ -986,10 +986,17 @@ def parse_tool_call(tool_call) -> tuple[str, dict | str]:
if isinstance(tool_call, str):
try:
tool_call_dict = ast.literal_eval(tool_call)
# We use json.loads instead of ast.literal_eval to prevent DoS attacks
# and code execution vulnerabilities from malicious or deeply nested inputs.
# Using extract_json allows us to handle markdown formatting robustly.
try:
tool_call_dict = extract_json(tool_call)
except ValueError:
tool_call_dict = json.loads(tool_call)
if not isinstance(tool_call_dict, dict):
tool_call_dict = {}
except (ValueError, SyntaxError):
except (json.JSONDecodeError, ValueError):
tool_call_dict = {}
tool_name = tool_call_dict.get("name", "Unknown Tool")