T09 · Insecure Skill Coding Practices
- Location
scripts/baseline.py:138- Finding
Unrestricted Download and Extraction of Remotely Supplied Archives
- Content
View full analysis
Vulnerability Details
File Location:
scripts/baseline.py:138-165;scripts/vuln.py:176-200
Vulnerability Type: Unsafe remote archive handling
Risk Level: HighVulnerable Code
scripts/baseline.py:python async def download_and_extract_async(link, account_id, prefix): """Asynchronously download a ZIP, extract it, and rename it.""" zip_path = Path(f"{prefix}-{account_id}-{TODAY}.zip") print(f" [download] account {account_id}...") loop = asyncio.get_event_loop() await loop.run_in_executor(None, _download_with_timeout, link, zip_path) with zipfile.ZipFile(zip_path) as zf: names = zf.namelist() zf.extractall(path=zip_path.parent) extracted = zip_path.parent / names[0] output_path = Path(f"{prefix}-{account_id}-{TODAY}.xlsx") if extracted != output_path: extracted.rename(output_path) if zip_path.exists(): zip_path.unlink() return str(output_path) def _download_with_timeout(link, output_path): """Download a file with a timeout.""" with urllib.request.urlopen(link, timeout=DOWNLOAD_TIMEOUT_SECONDS) as response: with Path(output_path).open("wb") as fp: shutil.copyfileobj(response, fp)scripts/vuln.py:python async def download_and_extract_async(link, account_id, prefix): """Download a ZIP, extract it, and rename it.""" zip_path = Path(f"{prefix}-{account_id}-{TODAY}.zip") loop = asyncio.get_event_loop() await loop.run_in_executor(None, _download_with_timeout, link, zip_path) with zipfile.ZipFile(zip_path) as zf: names = zf.namelist() zf.extractall(path=zip_path.parent) extracted = zip_path.parent / names[0] output_path = Path(f"{prefix}-{account_id}-{TODAY}.xlsx") if extracted != output_path: extracted.rename(output_path) if zip_path.exists(): zip_path.unlink( ...[truncated 2838 chars]- Remediation
View remediation
Remediation Suggestions
- Parse the returned URL and require
https. - Allowlist the documented Alibaba Cloud export domains and reject redirects to unapproved hosts.
- Stream the response while enforcing a strict maximum compressed size.
- Open the archive before extraction and require exactly one expected regular
.xlsxmember. - Reject absolute paths, parent-directory components, nested paths, symbolic links, duplicate names, and non-workbook extensions.
- Calculate the declared total expanded size and reject archives exceeding a conservative limit.
- Extract only the validated member rather than calling
extractall. - Use
tempfile.TemporaryDirectorywith restrictive permissions and move the validated workbook to the final location only after successful inspection. - Refuse to overwrite existing output files unless the user explicitly requests replacement.
- Delete partial downloads and extracted files in a
finallyblock. - Apply the same hardened helper to both
baseline.pyandvuln.py.
- Parse the returned URL and require
