Back to skill

Security audit

douyin-video

Security checks for vulnerabilities and agentic risk

Overview

This Douyin downloader mostly matches its stated purpose, but it accepts and follows unvalidated URLs and can write unbounded downloads to disk, so users should review it before installing.

Install only if you are comfortable with this skill making outbound requests to URLs it is given or extracts, and with it replacing ~/.openclaw/workspace/douyin-downloads/douyin_last.mp4 on each run. Prefer running it in a sandbox with restricted outbound networking and storage limits, and use it only for videos you are authorized to download and share.

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/douyin.js:29
Finding

Unrestricted URL Fetching and Redirect Following Enables SSRF

Content
View full analysis
{ const client = url.startsWith('https') ? https : http; const req = client.get(url, { headers: HEADERS }, (res) => { if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { httpRequest(res.headers.location).then(resolve).catch(reject); return; } let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => resolve(data)); }); req.on('error', reject); req.setTimeout(30000, () => { req.destroy(); reject(new Error('Request timeout')); }); }); } ``` The request destination originates directly from a command-line argument: ```js const shareUrl = process.argv[2]; if (!shareUrl) { console.error('Usage: node douyin.js '); process.exit(1); } const html = await httpRequest(shareUrl); ``` ### Technical Analysis The Skill passes an attacker-controlled URL directly to Node.js HTTP or HTTPS clients without validating its protocol, hostname, port, or resolved IP address. Despite being documented as a Douyin downloader, the implementation does not restrict requests to Douyin domains. HTTP redirects are recursively followed using the unvalidated `Location` header. Consequently, validating only the initial URL outside this function would not be sufficient: a permitted public endpoint could redirect the request to localhost, a private address, a link-local address, or another prohibited destination. The redirect implementation also lacks a redirect-count limit. A redirect loop can therefore cause repeated outbound requests and continued promise recursion until an error or resource exhaustion occurs. ### Attack Path 1. An attacke ...[truncated 1480 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/douyin.js:75
Finding

Unvalidated and Unbounded Media Download Enables Arbitrary Network Access and Disk Exhaustion

Content
View full analysis
{ const client = url.startsWith('https') ? https : http; const file = fs.createWriteStream(outputPath); const req = client.get(url, { headers: HEADERS }, (res) => { if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { downloadVideo(res.headers.location, outputPath).then(resolve).catch(reject); return; } res.pipe(file); file.on('finish', () => { file.close(); resolve(); }); }); req.on('error', (e) => { fs.unlink(outputPath, () => {}); reject(e); }); req.setTimeout(60000, () => { req.destroy(); fs.unlink(outputPath, () => {}); reject(new Error('Download timeout')); }); }); } ``` The remotely supplied playback address is used directly: ```js const playUrl = item.video.play_addr.url_list[0]; return { video_id: item.aweme_id, title: item.desc, author: item.author.nickname, digg_count: item.statistics.digg_count, share_count: item.statistics.share_count, collect_count: item.statistics.collect_count, play_url: playUrl }; ``` ```js await downloadVideo(info.play_url, outputPath); ``` ### Technical Analysis The media URL is extracted from remotely retrieved HTML and passed directly to the downloader. The implementation does not validate the media hostname, resolved IP, protocol, port, or redirect destinations. A crafted page matching the expected JSON structure can therefore provide an attacker-selected `play_url`. The downloader pipes the response directly to a fixed `.mp4` file without checking: - Whether the response has a successful status code. - W ...[truncated 2368 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The documented behavior does not fully match the operational behavior: the skill writes to a fixed local path, deletes previous content, and the advertised 'send' action is not actually described or implemented. This mismatch is dangerous because users and orchestrators may approve a simple downloader while the skill also performs persistent filesystem modification and destructive deletion.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill invokes a Node.js script but declares no explicit tool scope or permissions, leaving its runtime capabilities opaque to users and reviewers. In practice this can conceal access to environment variables or other host resources, which increases the chance of unintended data exposure or over-privileged execution.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

This markdown file describes parsing Douyin links, downloading videos locally, and sending them back, but its warnings only cover file retention and overwrite behavior. Because the skill handles third-party media content and redistribution-like behavior, the user-facing description should disclose legal/privacy-sensitive implications so users understand the impact before use.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script unconditionally deletes a previously downloaded file at a fixed path before saving a new one, with no confirmation, backup, or uniqueness in naming. This can cause unintended data loss and is more concerning in an agent skill context because repeated or automated invocations can silently overwrite or remove prior user content.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The Accept-Language header is hard-coded to zh-CN/zh, which enforces a specific language/locale for all requests. The file does not offer a language option or explain why this locale restriction is necessary, which is a natural-language locale policy concern.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.