Back to skill

Security audit

Douyin Hot Trend

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly fetches Douyin trends, but it includes under-documented Telegram-oriented output and an unsafe helper that can execute shell commands if given a crafted argument.

Review before installing. The basic Douyin trend fetcher is straightforward, but avoid using scripts/get-hot-trend.js with untrusted arguments, and check whether you want Telegram-formatted output with a hard-coded chat_id in the package. Prefer running only the documented scripts/douyin.js command unless the cron/Telegram workflow is intentionally desired.

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 (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/get-hot-trend.js:13
Finding

OS Command Injection Through an Unvalidated CLI Argument

Content
View full analysis

Vulnerability Details

File Location: scripts/get-hot-trend.js, lines 13–19 and line 73
Vulnerability Type: OS command injection
Risk Level: High

Vulnerable Code

javascript
function getHotTrend(limit = 10) {
  try {
    const scriptPath = path.join(__dirname, 'douyin.js');
    const output = execSync(`node "${scriptPath}" hot ${limit}`, {
      encoding: 'utf-8',
      cwd: path.dirname(scriptPath)
    });

The value passed to the vulnerable function originates directly from a command-line argument:

javascript
const limit = process.argv[2] || 10;

console.log('开始获取抖音热榜...');
const hotTrendData = getHotTrend(limit);

Technical Analysis

The limit value is obtained from process.argv[2] without type validation, range enforcement, or shell escaping. It is then interpolated into a command string passed to child_process.execSync().

execSync() executes the supplied string through a system shell. Consequently, shell metacharacters contained in limit, such as command separators or command substitutions, are interpreted by the shell rather than treated as a single numeric argument.

Although the normal purpose of this value is to specify the number of hot-trend entries, an attacker who can influence the script's CLI arguments can append an arbitrary operating-system command.

Attack Path

  1. An attacker gains the ability to invoke the helper script directly or influence arguments supplied by an Agent, cron wrapper, automation workflow, or other caller.

  2. The attacker supplies a crafted second argument containing a valid-looking limit followed by a shell command. A harmless proof of concept would be:

    bash
    node scripts/get-hot-trend.js '10; touch /tmp/douyin-command-injection'
    
  3. Line 73 assigns the entire crafted string to limit.

  4. getHotTrend() interpolates that string into the command passed to execSync().

  5. The system shell e ...[truncated 1199 chars]

Remediation
View remediation

Remediation Suggestions

  1. Avoid invoking a shell. Replace execSync() with execFileSync() or spawnSync() and pass arguments as a separate array:

    javascript
    const { execFileSync } = require('child_process');
    
    function getHotTrend(limit = 10) {
      try {
        const scriptPath = path.join(__dirname, 'douyin.js');
        const output = execFileSync(
          process.execPath,
          [scriptPath, 'hot', String(limit)],
          {
            encoding: 'utf-8',
            cwd: path.dirname(scriptPath)
          }
        );
        return output;
      } catch (error) {
        console.error('Failed to retrieve the Douyin hot list:', error.message);
        return null;
      }
    }
    
  2. Validate the argument before execution and reject anything other than a bounded positive integer:

    javascript
    const rawLimit = process.argv[2] ?? '10';
    
    if (!/^\d+$/.test(rawLimit)) {
      throw new Error('The limit must be a positive integer');
    }
    
    const limit = Number(rawLimit);
    
    if (!Number.isSafeInteger(limit) || limit < 1 || limit > 50) {
      throw new Error('The limit must be between 1 and 50');
    }
    
  3. Prefer importing the retrieval logic as a JavaScript module instead of launching another Node.js process. This removes the command-execution boundary entirely.

  4. Run the Skill under a least-privileged account with restricted filesystem access and without unnecessary secrets in its environment.

  5. Add regression tests using shell metacharacters, command substitutions, whitespace, negative values, excessively large values, and non-numeric input. Tests should verify that invalid values are rejected and that no secondary command is executed.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (24)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

声明描述的是一个单纯的抖音热榜数据获取与输出能力,但代码除获取和解析热榜外,还具备未声明的消息投递集成行为:它专门格式化 Telegram 消息、包含固定 Telegram chat_id/channel 字段,并生成供外部发送工具使用的 JSON。这属于超出“获取榜单数据”范围的实质性能力。此外,代码会将结果保存到本地文件,声明中也未体现。另一方面,声明提到会输出封面图(如有),但该代码片段并未解析或输出封面图字段。总体上,代码的主要目的更接近“定时整理抖音热榜并推送到 Telegram”,与声明存在明显行为不一致。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

该代码的核心功能与“获取抖音热榜/热搜榜并输出标题、热度、链接、封面”大体相关,但描述中声称覆盖‘热门视频、挑战赛、音乐等多领域热门内容’,这一点在实现中没有体现。实现只访问单一接口 www.douyin.com/aweme/v1/hot/search/list/,并从 data.data.word_list 提取热搜词条,属于热搜/搜索榜,而非多榜单聚合抓取。因此描述范围明显大于实际行为,构成描述与行为不一致。额外输出 label/type 属于轻微未声明行为,但主要不匹配点是宣称的多领域内容抓取能力并不存在。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

主要功能方向基本相关,都是获取抖音热点数据,但声明明显扩大了覆盖范围。代码只访问一个热搜榜接口,返回的是 word_list 热搜词条,并未实现热门视频、挑战赛、音乐等多榜单或多领域内容抓取。因此描述对能力范围有实质性夸大,构成描述与行为不一致。输出封面、标题、热度和链接这一点与声明基本一致;额外输出标签和类型不是安全层面的严重问题。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

声明强调获取较全面的抖音热榜/热搜榜数据,并输出标题、热度值、跳转链接及封面图。但从提供代码看,它只是执行 douyin.js hot 获取“hot”榜单结果,再从文本中解析标题与热度,固定格式化为 TOP 10 报告,并保存为文件。代码中没有任何链接、封面图字段提取逻辑,也没有展示对挑战赛、音乐或其他领域榜单的抓取入口。写文件和 stdout 输出属于实现细节,不构成问题;但核心输出能力和覆盖范围与声明存在实质差异,因此应判定为不匹配。

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/douyin.js hot

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/douyin.js hot

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The code formats content specifically for Telegram Markdown, embeds links for distribution, and builds a Telegram-targeted JSON payload despite the skill description only covering data retrieval/output. In agent ecosystems, hidden or undeclared communication integrations are dangerous because they expand the skill's operational scope and can be repurposed to send data or content to third-party channels without clear authorization.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The message timestamp is always formatted with the 'zh-CN' locale and 'Asia/Shanghai' timezone. This is a natural-language locale policy concern because the skill hard-codes a specific language/locale presentation without any user opt-in or documented justification that the skill is region-locked.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill prepares Telegram delivery metadata and output artifacts, including a hard-coded chat_id and channel designation, even though the stated skill purpose is only to retrieve and output Douyin hot-trend data. This creates an undeclared outbound messaging capability and risks data exfiltration, misuse of the skill for unsolicited messaging, or surprising behavior for operators who rely on the manifest for trust and scope.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest describes a skill that fetches Douyin hot-list data and outputs fields like title, popularity, link, and cover image. This file shows the skill also packaging the result for Telegram delivery, including chat_id, channel, and a scheduled push-style message, which goes beyond merely returning trend data.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The message content in L07 is entirely in Chinese, and the file provides no indication that the user opted into Chinese output or that the skill is intentionally restricted to a Chinese-language audience. This can violate language/locale policy when a skill imposes a specific language without user choice or explicit justification.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

A skill whose purpose is to fetch and present Douyin trending data would be expected to perform network retrieval and formatting, but not necessarily invoke subprocess execution. Using execSync introduces an execution capability that is broader than the stated data-fetching purpose.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest describes a skill that gets Douyin hot-list data and outputs titles, heat values, links, and cover images. This script not only retrieves/formats the data but also persists it to local text and JSON files, which is additional behavior beyond the stated read/output scope.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This JSON file specifies the timezone as "Asia/Shanghai" and presents the message/rawData entirely in Chinese, which indicates a fixed language/locale choice. Under the policy rules, forcing a specific language or locale without user opt-in or documented justification is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill title and description are entirely in Chinese, and the README does not indicate that the skill is region-specific or that users may choose another language. Under the policy scope, this can be a natural-language locale constraint without user opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The natural-language content of the skill, including its description and usage instructions, is entirely in Chinese. Under the policy for natural-language violations, forcing a specific language without user opt-in can be a locale-policy issue when no alternative or opt-in is provided.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file-level documentation states '直接发送到 Telegram', which implies active delivery. In practice, the code formats a Telegram message, writes local files, and prints output for another tool to capture; it does not perform any Telegram API call or direct send operation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

This plain-text skill output forces a specific language/locale for all users and does not indicate that Chinese was selected by the user or that alternatives are available. Under the policy, locale-specific content without user opt-in can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The manifest says the skill outputs title, popularity, jump link, and cover image when available. The item objects only contain rank, title, popularity, link, and label; no cover image field appears anywhere, creating a mismatch between the declared output contract and actual behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The package description is written only in Chinese and the keywords include a locale-specific marker ("chinese"), which signals a language/locale constraint. The file does not provide an explicit user language choice or a documented justification that this skill is intentionally region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The request sets Accept-Language to prefer zh-CN, which imposes a specific language/locale behavior. Under the policy, forced locale selection without user choice or clear region-specific justification is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The request sets Accept-Language to zh-CN,zh;q=0.9,en;q=0.8, which imposes a specific language/locale preference. Under the policy, locale constraints should be optional or clearly justified; this file does not provide user opt-in or explain why the locale is required.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script formats output using a hard-coded 'zh-CN' locale and 'Asia/Shanghai' timezone, which imposes a specific language/locale behavior on all users. The file does not offer an opt-in, override, or documented region-specific justification for this constraint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

This plain-text skill file uses Chinese-only headings, labels, and content, which can constitute a language/locale policy issue if the skill is expected to be usable without forcing a specific language. There is no surrounding text indicating that Chinese output is optional, user-selected, or justified as a region-specific skill.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
cron-job.js:16

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/get-hot-trend.js:16