T09 · Insecure Skill Coding Practices
- Location
scripts/linux-desktop.py:14- Finding
OS Command Injection Through User-Controlled Command-Line Arguments
- Content
View full analysis
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: HighVulnerable 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_commandfu ...[truncated 2810 chars]- Remediation
View remediation
Remediation Suggestions
- Remove
shell=Trueand 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()- 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)])- Replace the
xwd | convertshell 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)- 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.
-
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. -
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.
- Remove
