T09 · Insecure Skill Coding Practices
- Location
add_task.sh:22- Finding
Arbitrary Python Code Execution Through Unsafely Interpolated Task Input
- Content
View full analysis
Vulnerability Details
File Location:
add_task.sh, lines 22–33
Vulnerability Type: Python code injection through an unquoted heredoc
Risk Level: Highbash # JSON 기록 python3 - <<PY >> "$LOG" import json event = { "id": "$ID", "ts": "$TS", "title": "$TITLE", "owner": "$OWNER" if "$OWNER" else None, "due": "$DUE" if "$DUE" else None, "status": "draft" if (not "$OWNER" or not "$DUE") else "open", "raw": "$TEXT" } print(json.dumps(event, ensure_ascii=False)) PYTechnical Analysis
The script places task attributes derived from user-controlled Telegram input directly into Python source code. The heredoc delimiter is unquoted, so Bash expands variables such as
TITLE,OWNER,DUE, andTEXTbefore passing the resulting program to Python.These values are inserted between Python quotation marks without escaping them as Python string literals. An attacker can consequently terminate or modify the intended string expression and introduce an arbitrary Python expression. For example, input shaped like the following can cause a command to execute while Python evaluates the generated dictionary:
text "+str(__import__('os').system('id'))+"The resulting
titleexpression would contain executable Python rather than an inert string:python "title": ""+str(__import__('os').system('id'))+"",JSON serialization occurs only after the dynamically constructed Python source has already been parsed and executed. Therefore, the use of
json.dumpsdoes not mitigate this vulnerability.Attack Path
- An attacker sends a crafted
/todomessage containing Python syntax in the task text. - The skill passes the full text as an argument to
add_task.sh, as directed bySKILL.md. - The script derives
TITLE,OWNER,DUE, andTEXTfrom that attacker-controlled argument. - Bash substitutes these values into the unquoted Python heredoc.
- The substituted content changes the syntax or semantics of the ...[truncated 1102 chars]
- An attacker sends a crafted
- Remediation
View remediation
Remediation Suggestions
Do not construct executable source code by interpolating user-controlled data.
- Pass values to a fixed Python program through positional arguments or environment variables:
bash python3 - "$ID" "$TS" "$TITLE" "$OWNER" "$DUE" "$TEXT" <<'PY' >> "$LOG" import json import sys task_id, timestamp, title, owner, due, raw = sys.argv[1:] event = { "id": task_id, "ts": timestamp, "title": title, "owner": owner or None, "due": due or None, "status": "draft" if not owner or not due else "open", "raw": raw, } print(json.dumps(event, ensure_ascii=False)) PY- Quote the heredoc delimiter (
<<'PY') so that Bash does not perform parameter, command, or arithmetic expansion within the Python program. - Keep all user data outside the Python source and allow
json.dumpsto serialize it as data. - Add regression tests covering quotation marks, backslashes, newlines, Unicode, shell metacharacters, and Python expressions.
- Run the skill with least privilege and restrict its filesystem, credential, and network access to reduce the impact of any future injection flaw.
