T09 · Insecure Skill Coding Practices
- Location
scripts/list_openapi_meta_apis.py:29- Finding
Unsanitized CLI Arguments Permit Output Path Traversal
- Content
View full analysis
Vulnerability Details
File Location:
scripts/list_openapi_meta_apis.py, lines 29-72
Vulnerability Type: Path traversal and arbitrary file creation/overwrite
Risk Level: MediumVulnerable Code
python parser.add_argument("--product-code", default=DEFAULT_PRODUCT_CODE) parser.add_argument("--version", default=DEFAULT_VERSION) parser.add_argument("--output-dir", default=str(OUTPUT_DIR)) args = parser.parse_args() timeout = int(os.getenv("OPENAPI_META_TIMEOUT", "20")) output_dir = pathlib.Path(args.output_dir) output_dir.mkdir(parents=True, exist_ok=True) url = ( f"https://api.aliyun.com/meta/v1/products/{args.product_code}" f"/versions/{args.version}/api-docs.json" ) payload = fetch_json(url, timeout) raw_apis = payload.get("apis", {}) if isinstance(raw_apis, dict): api_names = sorted(raw_apis.keys()) elif isinstance(raw_apis, list): names = [] for item in raw_apis: if isinstance(item, dict): name = item.get("name") or item.get("apiName") if name: names.append(name) elif isinstance(item, str): names.append(item) api_names = sorted(set(names)) else: api_names = [] 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 script incorporates the user-controlled
--product-codeand--versionvalues directly into output filenames without validating path separators, traversal co ...[truncated 2183 chars]- Remediation
View remediation
Remediation Suggestions
-
Validate
--product-codeand--versionagainst a strict allowlist before using them in URLs or filenames. For example, permit only letters, digits, periods, underscores, and hyphens:python import re SAFE_COMPONENT = re.compile(r"^[A-Za-z0-9._-]+$") def validate_component(value: str, name: str) -> str: if not SAFE_COMPONENT.fullmatch(value): raise ValueError(f"Invalid {name}") return value -
Resolve the output directory and each generated file, then verify containment before writing:
python output_dir = pathlib.Path(args.output_dir).resolve() json_file = (output_dir / f"{product}_{version}_api_docs.json").resolve() if output_dir not in json_file.parents: raise ValueError("Output path escapes the selected output directory") -
If arbitrary output locations are unnecessary, remove
--output-diror require the resolved directory to remain beneathoutput/alicloud-ai-chatbot/. -
Reject absolute path fragments,
..components, and both POSIX and Windows path separators explicitly. -
Use exclusive creation or an explicit overwrite flag when replacing existing files is not required, reducing accidental or malicious file replacement.
-
Add tests covering
../, absolute paths, encoded separators, mixed path separators, and symlink-based output-directory escapes.
-
