Back to skill

Security audit

Douyin Download

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent video-downloader skill, but it reuses exported browser cookies and navigates/downloads from insufficiently validated URLs, creating review-worthy security risk.

Install only if you are comfortable giving the skill access to exported Douyin/TikTok cookies and local network-capable browser automation. Use it only with trusted Douyin/TikTok URLs, keep the cookie file limited and protected, choose a dedicated download directory, and avoid running it where internal web services or sensitive local files are reachable.

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/download.py:20
Finding

Unrestricted Browser Navigation Enables Server-Side Request Forgery

Content
View full analysis

Vulnerability Details

File Location: scripts/download.py, lines 20-54
Vulnerability Type: Unvalidated URL navigation / server-side request forgery
Risk Level: High

Vulnerable Code

python
def download(video_url, output_path, cookie_file):
    os.environ['HTTPS_PROXY'] = PROXY
    os.environ['HTTP_PROXY'] = PROXY

    from playwright.sync_api import sync_playwright

    pw_cookies = load_cookies(cookie_file)
    print(f"Loaded {len(pw_cookies)} Douyin cookies")

    video_url_found = [None]

    def handle_response(response):
        url = response.url
        if video_url_found[0]:
            return
        if 'douyinvod.com' in url and ('video/tos' in url or 'video/m/v' in url):
            video_url_found[0] = url
            print(f"Video URL intercepted: {url[:80]}...")

    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        ctx = browser.new_context(
            user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36'
        )
        for c in pw_cookies:
            try:
                ctx.add_cookies([c])
            except Exception as e:
                pass

        page = ctx.new_page()
        page.on('response', handle_response)

        print(f"Loading {video_url} ...")
        page.goto(video_url, wait_until='domcontentloaded', timeout=30000)

Technical Analysis

The caller-controlled video_url is passed directly to Playwright's page.goto() without validating its scheme, hostname, port, resolved address, or redirect destination. Nothing requires the destination to be an HTTPS Douyin or TikTok page.

Playwright therefore acts as a network-capable browser under the privileges and network visibility of the process running the Skill. A supplied URL can target loopback addresses, private network ranges, link-local services, or arbitrary Internet hosts. An a ...[truncated 2500 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse the input with urllib.parse.urlparse and accept only https URLs.
  2. Allowlist exact legitimate hostnames and carefully defined subdomains of Douyin and TikTok. Compare normalized hostnames rather than searching the entire URL for a substring.
  3. Reject URLs containing embedded credentials, unsupported ports, malformed internationalized hostnames, or IP-address literals.
  4. Resolve the hostname and reject loopback, private, link-local, multicast, reserved, and unspecified IP ranges for both IPv4 and IPv6.
  5. Validate every redirect destination before allowing navigation to continue. Playwright request routing can abort navigation or subresource requests to disallowed origins.
  6. Apply an outbound network allowlist to browser requests so attacker-controlled pages cannot contact internal services.
  7. Load account cookies only after the initial URL and redirect chain have been validated.
  8. Use a dedicated, least-privileged browser environment with restricted network access and no access to local administrative interfaces.
  9. Fail closed when URL parsing, DNS resolution, or destination validation is ambiguous.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/download.py:31
Finding

Substring-Based Media URL Validation Allows Arbitrary Content Download

Content
View full analysis

Vulnerability Details

File Location: scripts/download.py, lines 31-37 and 63-76
Vulnerability Type: Improper URL validation and unbounded arbitrary file download
Risk Level: High

Vulnerable Code

python
def handle_response(response):
    url = response.url
    if video_url_found[0]:
        return
    if 'douyinvod.com' in url and ('video/tos' in url or 'video/m/v' in url):
        video_url_found[0] = url
        print(f"Video URL intercepted: {url[:80]}...")

if not video_url_found[0]:
    print("ERROR: Could not find video URL!")
    return False

# Download
print("Downloading...")
s = requests.Session()
s.proxies = {'http': PROXY, 'https': PROXY}
r = s.get(video_url_found[0], stream=True, timeout=120, headers={'Referer': 'https://www.douyin.com/'})
total = int(r.headers.get('Content-Length', 0))
print(f"Size: {total//1024//1024}MB")

downloaded = 0
with open(output_path, 'wb') as f:
    for chunk in r.iter_content(chunk_size=65536):
        f.write(chunk)
        downloaded += len(chunk)

Technical Analysis

The response handler determines whether a resource is a trusted Douyin video by searching for strings in the complete URL. This does not establish that the parsed hostname is douyinvod.com or an approved subdomain.

For example, an attacker-controlled response URL such as the following satisfies the condition even though its actual host is unrelated:

text
https://attacker.example/video/tos?source=douyinvod.com

Once such a response is observed, the URL is passed to requests.Session.get() and streamed directly to output_path. The download path lacks several required controls:

  • Redirect destinations are not restricted to approved CDN hosts.
  • raise_for_status() is not called.
  • The response content type is not verified as video.
  • The response body has no enforced maximum size.
  • A missing or falsified Content-Length does not ...[truncated 2203 chars]
Remediation
View remediation

Remediation Suggestions

  1. Parse intercepted URLs and validate the normalized hostname against an explicit allowlist of legitimate video CDN domains. Require either an exact hostname match or a dot-delimited approved subdomain; do not use substring matching.
  2. Require HTTPS and reject embedded credentials, unusual ports, IP literals, and malformed hostnames.
  3. Disable automatic redirects or inspect and approve every redirect target before following it.
  4. Call r.raise_for_status() before writing any response body.
  5. Validate the response Content-Type against an expected media allowlist, while recognizing that MIME checks must supplement rather than replace origin validation.
  6. Define a strict maximum download size. Check a valid Content-Length before writing and enforce the same byte limit while iterating so chunked or dishonest responses cannot bypass it.
  7. Restrict output paths to a dedicated download directory. Resolve the canonical path and verify that it remains beneath that directory.
  8. Refuse to overwrite existing files unless explicit overwrite behavior is required and confirmed.
  9. Download into a securely created temporary file using exclusive creation, validate the completed file, flush it safely, and atomically rename it to the final destination.
  10. Remove partial files when status validation, size checks, MIME checks, network operations, or writes fail.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (5)

YARA rule 'info_stealer': Information stealer patterns (credential harvesting, browser data theft) [malware]

High
Category
YARA Match
Confidence
75% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · SKILL.md (reported line 27)May include surrounding context.

来 / Just send the link, I'll handle the rest

  • 🔒 隐私安全 — Cookie 来自你自己的浏览器,不经过第三方 / Your cookies stay local, no third-party involved
  • ⚡ 即下即用 — 拦截真实视频直链,直接下载 / Intercepts real video stream, downloads directly

使用前提 | Prerequisites

项目说明
Chrome 扩展安装 Get cookies.txt (可选,如果无法下载再装)
导出 Cookie访问 douyin.com → 点扩展 → Export → 保存到 sessions/cookies/cookies.txt
代理Clash Verge 或任意 HTTP 代理,运行在 127.0.0.1:7897
Python 包playwright, requests

注意:Cookie 只需要导出一次,除非过期。文件保存在你自己的电脑上,不会上传。

使用方法 | Usage

发给我任意抖音链接即可:

text
https://www.douyin.com/video/7627894054088461611

我会自动下载并保存到 `sessions/video-downl

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill declares behavior that requires network access, cookie handling, and local file writes, but it does not declare a restrictive tool or permission scope. In an agent environment, this can lead to over-privileged execution and make it harder for users or the platform to understand and constrain what the skill is allowed to do.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The trigger language is broad enough to match generic 'save TikTok' or download requests, which can cause the skill to activate in situations the user did not intend. Because this skill performs network access and writes files automatically, accidental invocation increases the chance of unwanted downloads or use of sensitive local session material.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script loads browser-exported cookies from disk and injects them into an automated browser session, effectively reusing authenticated session state. This is dangerous because cookie files are sensitive credentials; if the skill runs without an explicit consent flow or clear warning, it can access account-bound content and normalize unsafe handling of session secrets, increasing risk of account misuse or leakage.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The skill description states that it downloads content but does not present a prominent warning that it will automatically write files to a local directory. In agent workflows, undisclosed side effects reduce user awareness and can lead to unexpected local data creation or storage in sensitive paths.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.