T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/schedule_call.py:196
- Finding
- OS Command Injection Through Scheduled Call Content## Vulnerability Details **File Location**: `scripts/schedule_call.py:196-209` **Vulnerability Type**: OS command injection through unsafe shell command construction **Risk Level**: Critical ### Vulnerable Code ```python def schedule_task(contact: str, phone_content: str, delay_seconds: int, time_desc: str): """Create a scheduled task; phone_content is the message played during the call.""" script_dir = os.path.dirname(__file__) main_script = os.path.join(script_dir, "main.py") python_exe = get_python_executable() if delay_seconds > 0: cmd = f"(sleep {delay_seconds} && {python_exe} {main_script} '{contact}' '{phone_content}' 0) &" subprocess.Popen(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) return True else: subprocess.run([python_exe, main_script, contact, phone_content, "0"]) return True ``` ### Technical Analysis The delayed-execution branch constructs a shell command by directly interpolating `phone_content` into a single-quoted argument and then executes that command with `shell=True`. `phone_content` originates from the command supplied by the user. Although parsing removes certain time expressions and digits, it does not reject or escape shell metacharacters such as single quotes, semicolons, parentheses, redirection operators, or comment characters. An attacker can therefore terminate the quoted argument and append arbitrary shell commands. The immediate-call branch correctly uses an argument list, but delayed calls use an unsafe shell string. Suppressing standard output and standard error also makes exploitation and execution failures less visible. ### Attack Path 1. An attacker submits a delayed outbound-call instruction containing a recognized contact and malicious message content. 2. `parse_command()` extracts the attacker-controlled text as `phone_content`. 3. `schedule_task()` i ...[truncated 908 chars]
- Remediation
- ## Remediation Suggestions - Remove `shell=True` and never construct commands through string interpolation. - Perform delayed execution in Python or use a scheduler that accepts an argument array. - Invoke the target script with a fixed argument list: ```python import time def run_delayed_call(contact, phone_content, delay_seconds): time.sleep(delay_seconds) subprocess.run( [python_exe, main_script, contact, phone_content, "0"], check=True, ) ``` - If a detached process is required, create a small Python worker that receives validated arguments without invoking a shell. - Validate message length and allowed characters as defense in depth, but do not rely on filtering as the primary fix. - Log scheduling and execution failures securely rather than discarding both output streams. - Run the Skill under a dedicated, least-privileged operating-system account with restricted filesystem and network access.
