T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/list_openapi_meta_apis.py:32
- Finding
- Output Path Traversal Through Unvalidated Product Code and Version Arguments## Vulnerability Details **File Location**: `scripts/list_openapi_meta_apis.py`, lines 32–33 and 69–78 **Vulnerability Type**: Path traversal and insufficient output-path validation **Risk Level**: Medium ### Vulnerable Code ```python parser.add_argument("--product-code", default=DEFAULT_PRODUCT_CODE) parser.add_argument("--version", default=DEFAULT_VERSION) ``` ```python json_file = output_dir / f"{args.product_code}_{args.version}_api_docs.json" md_file = output_dir / f"{args.product_code}_{args.version}_api_list.md" json_file.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8") md_lines = [ f"# {args.product_code} {args.version} API List", "", f"- Source: {url}", f"- API count: {len(api_names)}", "", ] md_lines.extend([f"- `{name}`" for name in api_names]) md_file.write_text("\n".join(md_lines) + "\n", encoding="utf-8") ``` ### Technical Analysis The `--product-code` and `--version` command-line arguments are accepted without format validation and are interpolated directly into filesystem paths. `pathlib.Path` does not automatically constrain a joined path to its intended parent directory. Values containing path separators and traversal components such as `..` can therefore cause the generated artifact path to resolve outside `output/aliyun-bdrc-backup/`. The base output directory is created, but parent directories introduced through malicious argument values are not created. Exploitation consequently requires the traversed destination directories to exist. In addition, the network request must return valid JSON before either file write is reached. These constraints reduce exploitability but do not enforce the documented output boundary. The fixed filename suffixes restrict the exact names an attacker can target, but the script may still create or overwrite matching files elsewhere under the executing user's writable filesystem. ### Attack Path 1. ...[truncated 1878 chars]
- Remediation
- ## Remediation Suggestions 1. Apply strict allowlist validation before using either argument: ```python import re PRODUCT_RE = re.compile(r"^[A-Za-z0-9_-]+$") VERSION_RE = re.compile(r"^\d{4}-\d{2}-\d{2}$") if not PRODUCT_RE.fullmatch(args.product_code): parser.error("Invalid product code") if not VERSION_RE.fullmatch(args.version): parser.error("Invalid API version") ``` 2. Resolve every output path and verify that it remains below the resolved output directory: ```python output_dir = pathlib.Path(args.output_dir).resolve() output_dir.mkdir(parents=True, exist_ok=True) json_file = ( output_dir / f"{args.product_code}_{args.version}_api_docs.json" ).resolve() md_file = ( output_dir / f"{args.product_code}_{args.version}_api_list.md" ).resolve() for candidate in (json_file, md_file): if not candidate.is_relative_to(output_dir): raise ValueError("Generated output path escapes the output directory") ``` 3. For compatibility with Python versions lacking `Path.is_relative_to()`, compare paths using `relative_to()` and reject `ValueError`. 4. Reject path separators, `.` components, `..` components, absolute paths, control characters, and platform-specific separators in all values used to construct filenames. 5. If overwriting existing artifacts is unnecessary, use exclusive file creation mode to reduce overwrite risk. 6. Add regression tests covering Unix and Windows path separators, absolute paths, nested traversal sequences, encoded traversal strings, and symlinks within the output directory.
