T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/reminder.py:99
- Finding
- Shell Command Injection Through Unescaped Habit Names in Reminder Scripts<![CDATA[ ## Vulnerability Details **File Location**: `scripts/reminder.py:99-143` **Vulnerability Type**: Shell command injection in generated executable scripts and cron instructions **Risk Level**: High ### Vulnerable Code ```python if plat == "macos": # Create a launchd plist or use osascript-based reminder script_content = f'''#!/bin/bash osascript -e 'display notification "Time for: {habit["name"]}" with title "HabitChat Reminder"' echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] {habit["name"]}: Reminder fired" >> "{REMINDERS_LOG}" ''' script_path = DATA_DIR / f"reminder_{habit['id']}.sh" script_path.write_text(script_content) os.chmod(script_path, 0o755) result["method"] = "macos-notification" result["script"] = str(script_path) result["instructions"] = ( f"Reminder script created at {script_path}. " f"To activate, add a cron job: crontab -e and add:\n" f"{minute} {hour} * * * {script_path}" ) result["cron_line"] = f"{minute} {hour} * * * {script_path}" elif plat == "linux-desktop": script_content = f'''#!/bin/bash notify-send "HabitChat" "Time for: {habit["name"]}" --icon=dialog-information echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] {habit["name"]}: Reminder fired" >> "{REMINDERS_LOG}" ''' script_path = DATA_DIR / f"reminder_{habit['id']}.sh" script_path.write_text(script_content) os.chmod(script_path, 0o755) result["method"] = "linux-notify-send" result["script"] = str(script_path) result["instructions"] = ( f"Reminder script created at {script_path}. " f"To activate, add a cron job: crontab -e and add:\n" f"{minute} {hour} * * * DISPLAY=:0 {script_path}" ) result["cron_line"] = f"{minute} {hour} * * * DISPLAY=:0 {script_path}" else: # Headless / unknown - log file only result["method"] = "log-file" result["instructions"] = ( f"No desktop notification available. Reminders will be logged to {REMINDERS_LOG}. " ...[truncated 3225 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Do not generate shell source from habit names.** Implement notification and logging operations directly in Python. For Linux notifications, use an argument array without a shell: ```python subprocess.run( ["notify-send", "HabitChat", f"Time for: {habit['name']}", "--icon=dialog-information"], check=False, shell=False, ) ``` Append reminder records using Python file operations rather than an `echo` command. 2. **Use a fixed helper program for scheduled execution.** The cron entry should contain only a trusted Python executable, a fixed script path, and a validated habit ID. The helper should load the display name from JSON at runtime and must never interpret it as shell code. 3. **Validate habit identifiers and reminder times.** - Require habit IDs to match their expected hexadecimal format. - Parse the reminder time using `datetime.strptime(value, "%H:%M")`. - Convert the parsed hour and minute back to integers before using them in scheduling instructions. - Reject control characters, including carriage returns and newlines, in values used in configuration or generated instructions. 4. **If shell generation cannot be removed, quote every dynamic shell argument.** Use `shlex.quote()` for each separately interpolated argument. Do not interpolate untrusted values inside pre-existing single- or double-quoted shell strings. This is a secondary defense and is less robust than eliminating generated shell code. 5. **Create scripts with restrictive permissions.** If executable helper files remain necessary, use mode `0700` rather than `0755` and ensure `~/.habitchat` is not writable by other users. 6. **Make scheduling lifecycle management explicit.** Record the exact cron entry, provide an unambiguous removal procedure, and ensure disabling a reminder removes or disables the corresponding scheduled entry where feasible and only with explicit user authorization. 7. **Add re ...[truncated 244 chars]
