T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/run_complete_qc.py:41
- Finding
- Shell Command Injection Through Unquoted Path Interpolation## Vulnerability Details **File Location**: `scripts/run_complete_qc.py`, lines 41–45, 119–126, 240–246, and 273–278 **Vulnerability Type**: OS command injection **Risk Level**: Medium ### Vulnerable Code ```python def run_command(cmd, description): """运行命令并记录""" log(f"开始: {description}") log(f"命令: {cmd}") result = subprocess.run(cmd, shell=True, capture_output=True, text=True) ``` ```python cmd = f""" cd-hit -i {input_file} \ -o {output_file} \ -c 0.90 \ -n 5 \ -M 0 \ -T 8 """ if not run_command(cmd, "CD-HIT 去冗余"): return None ``` ```python cmd = f""" mafft --localpair \ --maxiterate 1000 \ --thread 8 \ {input_file} 1> {output_file} 2> {log_file} """ if not run_command(cmd, "MAFFT 多序列比对"): return None ``` ```python cmd = f""" trimal -in {input_file} \ -out {output_file} \ -automated1 """ if not run_command(cmd, "trimAl 比对修剪"): return None ``` ### Technical Analysis The pipeline constructs shell commands by directly interpolating `input_file`, `output_file`, and `log_file` into command strings. These strings are passed to `subprocess.run` with `shell=True`. Shell metacharacters contained in an interpolated path are consequently interpreted as shell syntax rather than as part of a filename. Relevant metacharacters include semicolons, command substitutions, pipes, redirection operators, and newline characters. The bundled `main()` currently obtains its initial input from a hardcoded path, which limits direct exploitation through the documented command line. However, the stage functions are ordinary module-level functions and can be imported and called with attacker-controlled path-like values. Future implementation of the documented input arguments would also make the flaw directly reachable unless command execution is corrected. ### Attack Path 1. A ...[truncated 1228 chars]
- Remediation
- ## Remediation Suggestions 1. Remove `shell=True` and pass every executable and argument as a separate list element: ```python def run_command(cmd, description, stdout=None, stderr=None): log(f"Starting: {description}") result = subprocess.run( cmd, shell=False, stdout=stdout, stderr=stderr, text=True, check=False, ) return result.returncode == 0 ``` 2. Construct CD-HIT and trimAl invocations as argument arrays: ```python cmd = [ "cd-hit", "-i", str(input_file), "-o", str(output_file), "-c", "0.90", "-n", "5", "-M", "0", "-T", "8", ] ``` 3. Handle MAFFT output redirection through Python file handles rather than shell operators: ```python cmd = [ "mafft", "--localpair", "--maxiterate", "1000", "--thread", "8", str(input_file), ] with output_file.open("w") as output_handle, log_file.open("w") as log_handle: result = subprocess.run( cmd, shell=False, stdout=output_handle, stderr=log_handle, text=True, check=False, ) ``` 4. Validate that input files exist and are regular files before execution. 5. Resolve and validate output paths against the selected output directory. 6. Avoid attempting to secure shell commands solely through manual quoting; argument arrays provide the appropriate command/argument boundary. 7. Run the pipeline under a dedicated, unprivileged account with access limited to the required input and output directories.
