T09 · Insecure Skill Coding Practices
- Location
scripts/coordinator.sh:104- Finding
Arbitrary Python Code Execution Through Unsafe Heredoc Interpolation
- Content
View full analysis
Vulnerability Details
File Locations:
scripts/coordinator.sh:104-120scripts/team.sh:69-94scripts/team.sh:121-146
Vulnerability Type: Python code injection through untrusted command-line arguments
Risk Level: HighVulnerable Code
scripts/coordinator.sh:104-120:bash python3 << PYEOF import json config_file = "$TEAM_DIR/config.json" try: with open(config_file, 'r') as f: config = json.load(f) if 'tasks' not in config: config['tasks'] = [] config['tasks'].append({ 'taskId': '$task_id', 'status': 'pending' }) with open(config_file, 'w') as f: json.dump(config, f, indent=2) except Exception as e: print(f"Update failed: {e}") PYEOFscripts/team.sh:69-94:bash python3 << PYEOF import json team_file = "$TEAM_DIR/team.json" try: with open(team_file, 'r') as f: team = json.load(f) if 'members' not in team: team['members'] = [] # Check whether the worker already exists exists = any(m.get('workerId') == '$worker_id' for m in team['members']) if not exists: team['members'].append({ 'workerId': '$worker_id', 'task': '$task_desc', 'status': 'running', 'startedAt': '$(date -u +%Y-%m-%dT%H:%M:%SZ)' }) with open(team_file, 'w') as f: json.dump(team, f, indent=2) print("Worker added to team") else: print("Worker already exists: $worker_id") except Exception as e: print(f"Error: {e}") PYEOFscripts/team.sh:121-146:bash python3 << PYEOF import json worker_file = "$worker_file" result = """$result""" try: with open(worker_file, 'r') as f: worker = json.load(f) worker['status'] = 'completed' worker['result' ...[truncated 2918 chars]- Remediation
View remediation
Remediation Suggestions
-
Never generate Python source code by interpolating command-line input.
-
Pass dynamic values as positional arguments:
bash python3 - "$TEAM_DIR/config.json" "$task_id" << 'PYEOF' import json import sys config_file = sys.argv[1] task_id = sys.argv[2] with open(config_file, "r", encoding="utf-8") as file: config = json.load(file) config.setdefault("tasks", []).append({ "taskId": task_id, "status": "pending", }) with open(config_file, "w", encoding="utf-8") as file: json.dump(config, file, indent=2) PYEOF -
Quote heredoc delimiters when the body must remain literal.
-
Apply the same
sys.argvor environment-variable pattern to worker IDs, descriptions, and results. -
Use
json.dumpfor every JSON document instead of constructing JSON with shell heredocs. -
Validate identifiers separately using a strict allowlist such as
^[A-Za-z0-9_-]+$. -
Return a nonzero exit status when Python state updates fail instead of catching errors and continuing as though the operation succeeded.
-
Add regression tests with single quotes, double quotes, triple quotes, backslashes, newlines, and Python statements in every user-controlled argument.
-
