T09 · Insecure Skill Coding Practices
- Location
scripts/generate.py:86- Finding
Unsanitized API response permits arbitrary filesystem paths and unrestricted remote downloads
- Content
View full analysis
Vulnerability Details
File Location:
scripts/generate.py, lines 86-95 and 192-212
Vulnerability Type: Untrusted path construction, unrestricted URL handling, and unbounded download
Risk Level: MediumVulnerable Code
python def download_file(url, output_path): """下载文件""" try: req = request.Request(url, headers={ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.0' }) with request.urlopen(req, timeout=60) as response: with open(output_path, 'wb') as f: f.write(response.read()) return True except Exception as e: print(f"下载文件失败: {e}") return Falsepython job_id = result.get("JobId") if not job_id: print("❌ 未获取到JobId") print(f"响应: {json.dumps(result, indent=2, ensure_ascii=False)}") sys.exit(1) print(f"✅ 任务提交成功,Job ID: {job_id}") # 等待完成 final_result = wait_for_completion(api_key, job_id) if not final_result: sys.exit(1) # 创建输出目录 today = datetime.now().strftime("%Y%m%d") output_dir = Path(args.output) / today / job_id output_dir.mkdir(parents=True, exist_ok=True) # 保存任务信息 info_path = output_dir / "info.json" with open(info_path, "w", encoding="utf-8") as f: json.dump(final_result, f, ensure_ascii=False, indent=2) # 下载3D模型 model_url = final_result.get("ResultUrl", "") if model_url: # 根据URL后缀判断格式 ext = model_url.split('.')[-1].split('?')[0] if '.' in model_url else "glb" model_path = output_dir / f"model.{ext}" if download_file(model_url, model_path): print(f"✅ 已保存: {model_path}")Technical Analysis
The script treats
JobIdandResultUrlfrom the remote API as trusted values.JobIdis directly appended to the user-selected output path. There is no validation requiring it to be a simple identifier and no canonical-path containment check. A response contai ...[truncated 3010 chars]- Remediation
View remediation
Remediation Suggestions
- Validate
JobIdusing a strict allowlist suitable for Tencent job identifiers, for example letters, digits, hyphens, and underscores with a conservative maximum length. - Reject absolute paths, path separators,
.components, and..components in all remote values used as filenames or directory names. - Resolve the base output directory and candidate destination with
Path.resolve(), then verify that the destination remains beneath the resolved base directory before creating or writing anything. - Require model URLs to use HTTPS and allowlist the exact Tencent download hosts documented for the service.
- Validate every redirect destination rather than only the initial URL. Disable automatic redirects or use a custom redirect handler that reapplies scheme, hostname, port, and IP-range checks.
- Resolve destination hosts and reject loopback, link-local, multicast, unspecified, and private-network addresses unless such access is explicitly required.
- Stream downloads in bounded chunks instead of calling
response.read()without a limit. Abort when a configured maximum model size is exceeded. - Check
Content-Lengthwhen present, while still enforcing the limit during streaming because that header may be absent or inaccurate. - Restrict output formats to an explicit allowlist such as
glbandobj. Prefer trusted response metadata or a fixed local extension rather than deriving an extension from arbitrary URL text. - Write downloads to a safely created temporary file within the validated output directory, verify size and expected format, and atomically rename the file only after validation succeeds.
- Use exclusive file creation or an explicit overwrite policy to prevent unintended replacement of existing files.
- Validate
