Back to skill

Security audit

Douyin Video Fetch

Security checks for vulnerabilities and agentic risk

Overview

This Douyin downloader is mostly coherent, but its code can open and download from arbitrary web URLs rather than only Douyin, creating avoidable network and disk-use risk.

Review before installing. Use it only with trusted Douyin inputs, run it with restricted outbound network access if possible, choose a controlled output directory, and avoid processing untrusted batch files until the script validates allowed hosts and enforces download size limits.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/fetch_video.py:338
Finding

Unrestricted URL Navigation Enables Server-Side Request Forgery

Content
View full analysis
str: item = (item or "").strip() if not item: return "" if item.startswith("http://") or item.startswith("https://"): return item if item.isdigit() and 8 <= len(item) <= 25: return f"https://www.douyin.com/video/{item}" return item ``` ### Technical Analysis Although the Skill is documented as a Douyin-specific downloader, `normalize_input_to_url` accepts any value beginning with `http://` or `https://` without validating its hostname, resolved IP address, port, or protocol security. The resulting URL is passed directly to Playwright's `page.goto`. Consequently, an attacker who can control a positional argument or a line in the batch input file can make the process navigate to arbitrary network destinations. This includes loopback services, private network addresses, link-local endpoints, or attacker-controlled public pages. Redirect destinations are also not restricted. Checking only the URL scheme is insufficient for SSRF prevention. Hostnames can resolve to private addresses, and an initially permitted public address can redirect to or be rebound to an internal address. ### Attack Path 1. An attacker supplies a crafted input through a positional argument or `--file`, such as an HTTP URL targeting a service reachable only from the host running the Skill. 2. `read_inputs` retains the input without security validation. 3. `normalize_input_to_url` accepts the URL unchanged because it starts with `http://` or `https://`. 4. `download_video` passe ...[truncated 1001 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch_video.py:284
Finding

Unvalidated Media URL Fetch Permits Secondary SSRF and Unbounded Disk Consumption

Content
View full analysis
{ const v = document.querySelector('video'); if (!v) return null; if (v.src && v.src.startsWith('http')) return v.src; const sources = Array.from(v.querySelectorAll('source')); const mp4 = sources.find(s => s.type === 'video/mp4'); return mp4 ? mp4.src : (sources[0] ? sources[0].src : null); }""") except Exception as e: logger.warning(f"DOM src evaluate failed: {e}") src = None if not src: logger.warning(f"No src extraction successful") return False # Only use if http/https if not src.startswith("http"): logger.warning(f"Invalid src: {src}") return False # Download logger.info(f"Downloading stream from {src}") # Use headers that mimic browser headers = { "User-Agent": await page.evaluate("navigator.userAgent"), "Referer": "https://www.douyin.com/" } async with aiohttp.ClientSession() as session: async with session.get(src, headers=headers, timeout=120) as resp: if resp.status in [200, 206]: with open(output_path, 'wb') as f: while True: chunk = await resp.content.read(1024*1024) if not chunk: break f.write(chunk) ``` ### Technical Analysis The media source can come from network interception, embedded page data, or a page-controlled DOM `` element. The only validation before the secondary request is `src.startswith("http")`, which is not a reliable URL or destination security check. The media URL is then fetched with `aiohttp`. No hostname o ...[truncated 2112 chars]
Remediation
View remediation
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (2)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill advertises commands that read local files (--file input.txt) and perform network downloads, but it does not declare any permissions or allowed-tools scope. In an agent environment, this creates an authorization gap: the runtime or reviewer cannot clearly constrain or approve file and network access before the skill is invoked.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The browser context is hard-coded with locale="zh-CN", which imposes a specific language/locale behavior on all users. The file does not offer an opt-in, fallback, or explanation that this locale restriction is required for a region-specific use case.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.