T09 · Insecure Skill Coding Practices
- Location
seedance.py:212- Finding
Shell Command Injection Through an API-Controlled Task Identifier
- Content
View full analysis
Vulnerability Details
File Location:
seedance.py, lines 212-230
Vulnerability Type: Shell command injection
Risk Level: High
Affected Platform: macOS, when video downloading is enabledVulnerable Code
python filename = f"seedance_{task_id}_{int(time.time())}.mp4" filepath = download_path / filename print(f"\nDownloading video to {filepath}...") try: urllib.request.urlretrieve(video_url, str(filepath)) print(f"Saved to: {filepath}") # Open on macOS if sys.platform == "darwin": os.system(f'open "{filepath}"') except Exception as e: print(f"Download failed: {e}", file=sys.stderr)Technical Analysis
The
task_idvalue is incorporated into a local filename without validation. For newly created tasks, this value originates from the remote Ark API response. It can also enter the same code path through the positional task identifier accepted by thewaitcommand.The resulting
filepathis interpolated into a command string passed toos.system(). Although the path is enclosed in double quotes, embedded double quotes and shell metacharacters are not escaped. Becauseos.system()invokes a command shell, a malicious task identifier can terminate the quoted argument and append an additional shell command.Exploitation requires the polling request for the crafted task identifier to produce a successful task response with a downloadable video URL. This could occur if the trusted remote API were compromised, returned attacker-controlled task metadata, or an attacker could otherwise control a compatible API response. The vulnerable shell call is macOS-specific and is reached only after the video download succeeds.
Attack Path
- The attacker causes the application to process a task identifier containing a quote and shell metacharacters.
- The corresponding task-status request returns a successful result and a valid downloadable
video_url.
...[truncated 1270 chars]
- Remediation
View remediation
Remediation Suggestions
-
Eliminate shell interpretation by replacing
os.system()with an argument-vector subprocess call:python import subprocess if sys.platform == "darwin": subprocess.run( ["open", str(filepath)], check=False, shell=False, ) -
Validate task identifiers before using them in filenames. Apply a strict allowlist matching the documented identifier format, for example:
python import re if not re.fullmatch(r"[A-Za-z0-9_-]{1,128}", task_id): raise ValueError("Invalid task identifier") -
Decouple remote identifiers from filesystem names. Prefer a locally generated UUID as the filename and retain the remote task identifier only as metadata.
-
Resolve the final destination and verify that it remains within the requested download directory before writing:
python download_root = Path(download_dir).expanduser().resolve() filepath = (download_root / safe_filename).resolve() if download_root not in filepath.parents: raise ValueError("Download path escapes the destination directory") -
Restrict downloaded video URLs to expected schemes and, where supported by the API contract, trusted hosts. Reject local-file schemes and unexpected redirects.
-
Add regression tests using task identifiers containing quotes, semicolons, command substitutions, control characters, and path separators. Verify that these inputs are rejected and never reach a shell.
-
