Back to skill

Security audit

douyin-video-parser

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed Douyin video transcription tool whose network, browser, model-download, and local file behaviors fit its stated purpose, with some install and local-temp safety caveats.

Install only if you are comfortable with a skill that runs Python, installs third-party packages, downloads a Whisper model, opens a headless browser, accesses Douyin/CDN network resources, and writes local transcript/report files. Use a dedicated output directory, avoid privacy-sensitive videos on shared machines, and prefer a virtual environment with pinned dependencies if you need stronger reproducibility.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (2)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:56
Finding
Unpinned third-party dependencies and remotely downloaded model artifacts<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:56-60`, `SKILL.md:70-73`, `scripts/transcribe.py:294-300`, `scripts/transcribe.py:488-491`, `scripts/transcribe.py:520-537` **Vulnerability Type**: Supply-chain exposure through mutable dependencies **Risk Level**: Medium ### Vulnerable Code ```bash pip3 install faster-whisper pip3 install websocket-client ``` ```python try: import websocket except ImportError: print("[ERROR] Missing websocket-client library. Install it with: pip install websocket-client", file=sys.stderr) return None, None ``` ```python try: import yt_dlp except ImportError: sys.exit("[ERROR] yt-dlp is not installed. Install it with: pip install yt-dlp") ``` ```python from faster_whisper import WhisperModel local_model = os.path.join(os.path.expanduser("~"), ".whisper-models-local") local_bin = os.path.join(local_model, "model.bin") if os.path.exists(local_bin) and os.path.getsize(local_bin) > 10_000_000: model = WhisperModel(local_model, device="cpu", compute_type="int8") else: model = WhisperModel( model_size, device="cpu", compute_type="int8", download_root=MODEL_DIR, ) ``` ### Technical Analysis The documented installation procedure retrieves `faster-whisper` and `websocket-client` without pinned versions, package hashes, or a dependency lock file. The implementation also optionally imports `yt_dlp` and allows `faster-whisper` to download model artifacts dynamically. Python packages can execute arbitrary code during installation and import. Because no reviewed versions or hashes are specified, the effective dependency code may change after the Skill itself has been audited. The model download is also accepted without an application-level expected digest. This behavior is related to the declared transcription and browser functionality, but the mutable supply-chain trust exceeds the minimum risk necessary to provide that functionality. ### Attack ...[truncated 1237 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a reviewed dependency lock file containing exact versions for direct and transitive dependencies. 2. Require hashes, for example through `pip install --require-hashes -r requirements.txt`. 3. Pin `faster-whisper`, `websocket-client`, `yt-dlp`, and their transitive dependencies to reviewed releases. 4. Use an explicitly trusted package index or an internally mirrored repository. 5. Record and verify expected checksums for downloaded model artifacts where the model distribution mechanism permits it. 6. Document a controlled update process in which dependency upgrades are reviewed and scanned before release. 7. Consider running transcription and browser extraction in a restricted environment with minimal filesystem and network access. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/transcribe.py:234
Finding
Predictable media files are written unsafely in a shared temporary directory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/transcribe.py:234-246`, `scripts/transcribe.py:1426`, `scripts/transcribe.py:1461-1465` **Vulnerability Type**: Predictable temporary file and symbolic-link race **Risk Level**: Medium ### Vulnerable Code ```python for i, u in enumerate(urls): tmp = os.path.join(TEMP_DIR, f"cdn_probe_{i}.mp4") try: req = urllib.request.Request(u, headers={ "User-Agent": DESKTOP_UA, "Referer": "https://www.douyin.com/", }) with urllib.request.urlopen(req, timeout=60) as resp: data = resp.read() if len(data) < 300 * 1024: continue with open(tmp, "wb") as f: f.write(data) ``` The main media file is similarly predictable: ```python mp4_path = os.path.join(TEMP_DIR, f"douyin_{video_id}.mp4") ``` It is later removed without verifying that it is the file originally created by this process: ```python if not args.keep_mp4: try: os.remove(mp4_path) except OSError: pass ``` ### Technical Analysis `TEMP_DIR` is the operating system's shared temporary directory. The Skill constructs filenames from predictable values: - `cdn_probe_0.mp4`, `cdn_probe_1.mp4`, and similar probe names. - `douyin_<video_id>.mp4`, where the video ID is normally public or visible in the command line. The files are opened with `open(path, "wb")`, which follows symbolic links and truncates an existing target. The implementation does not use exclusive creation, verify file ownership, reject symbolic links, or place the files inside a private per-run directory. On a multi-user system, another local account can pre-create one of these paths as a symbolic link to a file writable by the victim. When the Skill opens the path, downloaded media bytes are written to the symbolic-link target. Concurrent Skill runs can also overwrite or consume one another's media files. The final `os.remove()` removes the path entry rather t ...[truncated 1441 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create a private directory for each run: ```python with tempfile.TemporaryDirectory(prefix="douyin-transcribe-") as run_dir: mp4_path = os.path.join(run_dir, "video.mp4") ``` 2. Create temporary files through `tempfile.NamedTemporaryFile()` rather than predictable names. 3. Where a stable name is unavoidable, create files atomically with exclusive access using `os.open()` and `O_CREAT | O_EXCL`. 4. On supported platforms, use `O_NOFOLLOW` to reject symbolic links. 5. Verify with `os.lstat()` and `os.fstat()` that the opened object is a regular file owned by the current process user. 6. Keep CDN probe files inside the same private per-run directory and use randomized names. 7. Perform cleanup in a `finally` block by deleting the private directory rather than unlinking predictable shared paths. 8. Add concurrency tests and symbolic-link attack tests for all temporary media paths. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (10)

Ae1

High
Category
analysis-evasion
Content
python3 scripts/transcribe.py "https://www.douyin.com/video/7634579290163531035"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python3 scripts/transcribe.py "https://www.douyin.com/video/7634579290163531035"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python3 scripts/transcribe.py "https://www.douyin.com/video/7634579290163531035"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python3 scripts/transcribe.py "https://www.douyin.com/video/7634579290163531035"
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill explicitly instructs the agent to perform network access, shell/Python execution, and file reads/writes, but it does not declare an enforceable tool scope such as permissions or allowed-tools metadata. That mismatch is dangerous because a host agent may grant broader capabilities than reviewers expect, enabling the skill to launch browsers, install packages, download models, access remote content, and read generated files without machine-checkable restrictions.

Context-Inappropriate Capability

Medium
Confidence
87% confidence
Finding
The skill launches and drives a local browser through CDP, which is a substantially more privileged capability than simple HTTP fetching. Even though this code targets Douyin pages, CDP control can access browser-rendered content, trigger navigation, and harvest session-derived data, increasing privacy and attack surface if the skill is used in broader agent contexts or modified inputs.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The docstring states fetch_video_via_cdp returns (title, mp4_url, local_path) and even documents failure as (None, None, None). In multiple branches, the function instead returns only two values, contradicting the documented interface and intent.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
shutil.rmtree(profile, ignore_errors=True)

    print("      [cdp] 启动 headless 浏览器获取直链…")
    proc = subprocess.Popen(
        [browser, "--headless=new", "--disable-gpu", "--no-first-run",
         "--disable-extensions", "--mute-audio",
         f"--remote-debugging-port={port}", "--remote-allow-origins=*",
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Description-Behavior Mismatch

Low
Confidence
84% confidence
Finding
The manifest emphasizes a local, free pipeline without API keys, which suggests primarily on-device processing. However, when a local model is not already present, the code invokes WhisperModel with a model name and download_root, causing the model artifacts to be fetched externally at first run.

Natural-Language Policy Violations

Low
Confidence
90% confidence
Finding
This code file contains a natural-language locale constraint in the HTML template via `<html lang="zh-CN">`. The skill also defaults to Chinese-oriented output, but does not offer a user-facing locale choice for the report itself or explain why the report must always be Chinese, which conflicts with the policy against forcing a specific language/locale without opt-in.

Static analysis

No suspicious patterns detected.