T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/linux-desktop.py:14
- Finding
- OS Command Injection Through User-Controlled Command-Line Arguments## Vulnerability Details **File Location**: `scripts/linux-desktop.py:14-21, 25-30, 38-46, 103-115, 168, 178-179, 247, 261` **Vulnerability Type**: OS command injection caused by unsafe shell invocation **Risk Level**: High ### Vulnerable Code ```python def run_command(cmd): """运行 shell 命令""" try: result = subprocess.run( cmd, shell=True, capture_output=True, text=True, timeout=30 ) return result.returncode == 0, result.stdout.strip(), result.stderr.strip() except subprocess.TimeoutExpired: return False, "", "Command timed out" except Exception as e: return False, "", str(e) def take_screenshot(output_path=None): """截图""" if not output_path: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") output_path = f"/tmp/screenshot_{timestamp}.png" success, stdout, stderr = run_command(f"scrot '{output_path}'") def take_window_screenshot(window_id=None, output_path=None): """截图指定窗口""" if not output_path: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") output_path = f"/tmp/window_{timestamp}.png" if window_id: success, stdout, stderr = run_command( f"xwd -id {window_id} | convert xwd:- '{output_path}'" ) else: success, stdout, stderr = run_command( f"xwd -root | convert xwd:- '{output_path}'" ) def type_text(text): """输入文本""" success, stdout, stderr = run_command(f"xdotool type '{text}'") def key_press(key): """按键""" success, stdout, stderr = run_command(f"xdotool key {key}") ``` The affected values are populated directly from command-line arguments: ```python output = sys.argv[2] if len(sys.argv) > 2 else None window_id = sys.argv[2] if len(sys.argv) > 2 else None output = sys.argv[3] if len(sys.argv) > 3 else None text = sys.argv[2] key = sys.argv[2] ``` ### Technical Analysis The shared `run_command` fu ...[truncated 2810 chars]
- Remediation
- ## Remediation Suggestions 1. Remove `shell=True` and execute every utility with an argument list: ```python def run_command(args): result = subprocess.run( args, shell=False, capture_output=True, text=True, timeout=30, check=False, ) return result.returncode == 0, result.stdout.strip(), result.stderr.strip() ``` 2. Convert straightforward calls to argument arrays: ```python run_command(["scrot", output_path]) run_command(["xdotool", "type", "--", text]) run_command(["xdotool", "key", key]) run_command(["xdotool", "mousemove", str(x), str(y)]) run_command(["xdotool", "click", str(button)]) ``` 3. Replace the `xwd | convert` shell pipeline with two processes connected explicitly: ```python xwd_args = ["xwd", "-id", window_id] if window_id else ["xwd", "-root"] xwd = subprocess.Popen(xwd_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) convert = subprocess.run( ["convert", "xwd:-", output_path], stdin=xwd.stdout, capture_output=True, timeout=30, check=False, ) if xwd.stdout: xwd.stdout.close() xwd.wait(timeout=30) ``` 4. Validate arguments independently of shell removal: - Restrict window IDs to the formats accepted by `xwd`, such as a decimal integer or a strictly validated hexadecimal X11 ID. - Allow only supported key-specification syntax. - Restrict mouse buttons to the documented set unless broader support is required. - Validate output paths according to the intended file-access policy. - Reject NUL bytes and malformed values. 5. Add regression tests using single quotes, semicolons, newlines, backticks, `$()` substitutions, redirections, and pipeline characters. Verify that each value is passed literally and cannot create additional processes. 6. Apply least privilege: run desktop automation only as the intended graphical user, never as root, and avoid exposing this command interface directly to untrusted input.
