T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/run_prediction.py:22
- Finding
- PowerShell Command Injection Through Unvalidated Prediction Date<![CDATA[ ## Vulnerability Details **File Location**: `scripts/run_prediction.py`, lines 22–38 **Vulnerability Type**: OS command injection through unsafe PowerShell command construction **Risk Level**: High ### Vulnerable Code ```python def run_prediction(start_date: str, samples: int, output_dir: str): """ Execute batch prediction. Args: start_date: Prediction start date (YYYY-MM-DD) samples: Number of samples output_dir: Output directory used to locate the input file """ # Build command cmd = f'conda activate {CONDA_ENV} && python .\\batch_predict.py --start_date {start_date} --samples {samples}' print(f"执行预测: {cmd}") print(f"工作目录: {PREDICT_DIR}") result = subprocess.run( ['powershell', '-Command', cmd], cwd=PREDICT_DIR, capture_output=True, text=True ) ``` The externally supplied value originates from the command-line interface: ```python parser.add_argument('--start_date', required=True, help='预测开始日期 (YYYY-MM-DD)') parser.add_argument('--samples', type=int, required=True, help='采样次数') parser.add_argument('--output_dir', required=True, help='输出目录') parser.add_argument('--input_file', required=True, help='输入文件名') args = parser.parse_args() success = run_prediction(args.start_date, args.samples, args.output_dir) ``` ### Technical Analysis The `start_date` parameter is accepted as an unrestricted string. Although its help text states that the expected format is `YYYY-MM-DD`, the script does not parse or validate it as a date. The value is interpolated directly into `cmd`, which is then passed to `powershell -Command`. PowerShell interprets command separators, pipelines, redirections, subexpressions, and other shell metacharacters contained in that string. Consequently, a caller who can control `--start_date` can terminate or alter the intended `batch_predict.py` invocation and append additional PowerShell operations. The `samples` parameter is converted ...[truncated 1961 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Strictly validate and canonicalize the date** Parse the value with `datetime.strptime()` and reject any value that is not exactly in canonical `YYYY-MM-DD` format: ```python from datetime import datetime def validate_date(value: str) -> str: try: parsed = datetime.strptime(value, "%Y-%m-%d") except ValueError as exc: raise ValueError("start_date must use YYYY-MM-DD format") from exc canonical = parsed.strftime("%Y-%m-%d") if value != canonical: raise ValueError("start_date must use canonical YYYY-MM-DD format") return canonical ``` 2. **Avoid constructing a PowerShell command string** Resolve the intended Python executable or use `conda run`, then pass every argument as a separate list element without shell interpretation: ```python validated_date = validate_date(start_date) if not 1 <= samples <= 10000: raise ValueError("samples is outside the permitted range") result = subprocess.run( [ "conda", "run", "-n", CONDA_ENV, "python", ".\\batch_predict.py", "--start_date", validated_date, "--samples", str(samples), ], cwd=PREDICT_DIR, capture_output=True, text=True, shell=False, check=False, ) ``` 3. **Apply explicit bounds to numeric inputs** Although `samples` is parsed as an integer, enforce a reasonable minimum and maximum to prevent resource exhaustion or accidental denial of service. 4. **Do not rely on quoting as the primary defense** PowerShell escaping is complex and context-sensitive. Input validation and argument-array execution without a command shell should be used instead of attempting to escape attacker-controlled text. 5. **Limit execution privileges** Run the prediction process under a dedicated, non-administrative account ...[truncated 343 chars]
