Back to skill

Security audit

抖音爆款爬虫

Security checks for vulnerabilities and agentic risk

Overview

The skill is not clearly malicious, but it advertises Douyin scraping while returning generated example data and includes risky browser/setup behavior users should review before installing.

Install only if you are comfortable with a skill that may contact Douyin, install browser automation components, and create local files. Treat its current search and hot-list results as synthetic examples, not real Douyin data, unless the publisher replaces the mock generation with verified extraction and removes or contains risky browser setup choices.

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

T08 · Insecure Dependencies

Warning
Location
install.sh:40
Finding
Mutable and Unverified Playwright Dependency Installation<![CDATA[ ## Vulnerability Details **File Location**: `install.sh:40-41`; `requirements.txt:1` **Vulnerability Type**: T08: Insecure Dependencies **Risk Level**: Medium ### Vulnerable Code `install.sh:40-41`: ```bash pip install --upgrade pip pip install playwright ``` `requirements.txt:1`: ```text playwright>=1.40.0 ``` ### Technical Analysis The installation process retrieves executable Python packages without exact version pins, cryptographic hashes, or a reviewed lockfile. The lower-bound constraint in `requirements.txt` permits any newer Playwright release, while `install.sh` ignores the requirements file and installs whatever version is current at installation time. Python packages can execute code during build and installation. Consequently, installation behavior can change after the skill has been reviewed. This is a supply-chain weakness rather than evidence that the current Playwright package is malicious. The README also recommends mutable installation commands such as `pip install playwright` and `npx playwright install chromium`. No Node.js package manifest or lockfile is present in the audited project, so the documented Node.js installation path is not reproducible. ### Attack Path 1. An attacker compromises an allowed package release, distribution account, registry response, or transitive dependency. 2. A user executes `install.sh` or follows the documented manual installation procedure. 3. `pip` resolves the mutable requirement to the compromised or unexpectedly changed release. 4. Package build or installation code runs with the privileges of the user executing the installer. 5. The hostile package can access files, environment variables, network resources, and credentials available to that user. ### Impact Assessment Successful exploitation can execute arbitrary code with the installer user's privileges. If installation is performed by a privileged account or inside a sensitive agent workspace, the affected scope may include projec ...[truncated 167 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin Playwright and every transitive dependency to reviewed exact versions. 2. Generate a hash-locked requirements file, for example with `pip-compile --generate-hashes`. 3. Install with hash enforcement: ```bash python -m pip install --require-hashes -r requirements.txt ``` 4. Do not upgrade `pip` implicitly during ordinary skill installation; manage installer tooling through a separately reviewed process. 5. Add and commit a reviewed `package.json` and lockfile if Node.js support is retained. 6. Use `npm ci` instead of mutable `npm install`, and avoid executing unpinned packages through `npx`. 7. Run dependency installation as an unprivileged user in an isolated environment. ]]>

T08 · Insecure Dependencies

Error
Location
install_playwright_docker.py:27
Finding
Executable Browser Downloads Redirected to Third-Party Mirrors Without Independent Verification<![CDATA[ ## Vulnerability Details **File Location**: `install_playwright_docker.py:27-35` **Vulnerability Type**: T08: Insecure Dependencies **Risk Level**: High ### Vulnerable Code ```python def mode_native() -> None: env = os.environ.copy() env.setdefault("PLAYWRIGHT_DOWNLOAD_HOST", "https://npmmirror.com/mirrors/playwright") env.setdefault("PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST", "https://cdn.npmmirror.com/binaries/chrome-for-testing") venv_python = Path("venv/bin/python") venv_pip = Path("venv/bin/pip") if not venv_python.exists(): run([sys.executable, "-m", "venv", "venv"]) run([str(venv_pip), "install", "-r", "requirements.txt"], env=env) run([str(venv_python), "-m", "playwright", "install", "chromium"], env=env) ``` ### Technical Analysis Native installation changes Playwright's browser download endpoints to third-party mirror domains. Chromium is a native executable that will later process untrusted remote web content. The helper does not independently validate the downloaded artifact using a project-controlled checksum or signature. TLS protects the connection to the selected mirror but does not establish that a mirror-provided artifact is identical to the reviewed upstream artifact. A mirror compromise, artifact substitution, or trust-boundary failure could therefore introduce a modified browser binary. The use of `setdefault` also permits callers to supply arbitrary alternative download hosts through inherited environment variables. This is useful for configuration but increases the importance of explicit host validation and artifact verification. ### Attack Path 1. An attacker compromises a configured mirror, controls a caller-supplied download host, or substitutes a browser artifact through the distribution channel. 2. A user runs: ```bash python install_playwright_docker.py native ``` 3. Playwright downloads Chromium from the configured non-default endpoint. 4. The helper performs no project-lev ...[truncated 677 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use Playwright's official distribution endpoints unless an internally controlled and audited mirror is required. 2. Pin the Playwright package and corresponding browser revision exactly. 3. Verify browser archives against cryptographic hashes or signatures obtained through a separately trusted channel before installation or execution. 4. Reject arbitrary download-host environment variables unless explicitly enabled by an administrator. 5. Maintain an allowlist of approved HTTPS hosts and fail closed when an unapproved host is supplied. 6. Run browser installation and execution as an unprivileged user inside a disposable, network-restricted environment. 7. Record the package version, browser revision, source URL, and verified digest for auditability. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/douyin_scraper.js:34
Finding
Chromium Security Sandbox Explicitly Disabled While Rendering Remote Content<![CDATA[ ## Vulnerability Details **File Location**: `scripts/douyin_scraper.js:34-43` **Vulnerability Type**: T09: Insecure Skill Coding Practices **Risk Level**: High ### Vulnerable Code ```javascript async start() { console.log('🚀 启动浏览器...'); this.browser = await chromium.launch({ headless: this.headless, args: [ '--disable-blink-features=AutomationControlled', '--no-sandbox', '--disable-setuid-sandbox', ] }); this.page = await this.browser.newPage({ ``` ### Technical Analysis The JavaScript scraper launches Chromium with both `--no-sandbox` and `--disable-setuid-sandbox`. These flags remove important process-isolation controls intended to limit the consequences of browser renderer compromise. The scraper then navigates to remote Douyin pages. Browser content is inherently outside the local trust boundary and can exercise a large browser attack surface. Disabling the sandbox does not create a browser vulnerability by itself, but it substantially increases the impact of a renderer or browser exploit. The automation-evasion flag does not require disabling the sandbox. These options therefore exceed the privileges reasonably needed for the stated scraping task. ### Attack Path 1. The user invokes the Node.js search or hot-list command. 2. The scraper launches Chromium with its sandbox disabled. 3. Chromium loads remote page content from Douyin and associated resources. 4. Malicious or compromised content exploits a browser or renderer vulnerability. 5. Because the sandbox is disabled, the exploit has fewer isolation boundaries to escape before reaching resources available to the browser process. 6. Attacker-controlled code may operate with the privileges of the user running the scraper. ### Impact Assessment The potential scope includes all files, environment variables, local services, and network resources accessible to the scraper user. If run as root or in a broadly p ...[truncated 256 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove both sandbox-disabling arguments: ```javascript this.browser = await chromium.launch({ headless: this.headless, args: ['--disable-blink-features=AutomationControlled'] }); ``` 2. Run Chromium as a dedicated unprivileged user on a system that supports its normal sandbox. 3. Do not run the scraper as root. 4. If environmental constraints make sandboxing impossible, run the entire browser in a hardened disposable container or virtual machine with: - no host filesystem mounts unless strictly required; - a read-only root filesystem; - dropped Linux capabilities; - `no-new-privileges`; - restricted outbound networking; - memory and CPU limits; - no sensitive environment variables. 5. Keep Chromium and Playwright pinned to reviewed, security-supported versions. ]]>

other

Warning
Location
scripts/scraper.py:36
Finding
Fabricated Records Are Returned as Scraped Douyin Results<![CDATA[ ## Vulnerability Details **File Location**: `scripts/scraper.py:36-55,98-106`; equivalent behavior in `scripts/douyin_scraper.js:87-104,137-153` **Vulnerability Type**: other: Misleading Fabricated Output **Risk Level**: Medium ### Vulnerable Code Synthetic search-record generation in `scripts/scraper.py:36-55`: ```python def _mock_search(self, keyword: str, limit: int) -> list[VideoData]: today = date.today().isoformat() return [ VideoData( title=f"{keyword}相关视频 {i + 1}", description=f"这是关于{keyword}的示例描述", author=f"作者{i + 1}", play_count=10000 * (i + 1), like_count=1000 * (i + 1), comment_count=100 * (i + 1), share_count=50 * (i + 1), url=f"https://www.douyin.com/search/{keyword}", tags=[keyword, "热门"], publish_time=today, ) for i in range(min(limit, 10)) ] ``` The public operations always return mock records in `scripts/scraper.py:98-106`: ```python def search(self, keyword: str, limit: int) -> list[VideoData]: url = f"https://www.douyin.com/search/{keyword}" self._try_browser(url) return self._mock_search(keyword, limit) def hot(self, category: str, limit: int) -> list[VideoData]: url = "https://www.douyin.com/hot" self._try_browser(url) return self._mock_hot(category, limit) ``` The JavaScript implementation similarly constructs examples rather than extracting page data: ```javascript // 示例数据(实际使用时需要根据页面结构调整) for (let i = 0; i < Math.min(limit, 5); i++) { const video = new VideoData({ title: `${keyword}相关视频 ${i + 1}`, description: `这是关于${keyword}的视频描述`, author: `作者${i + 1}`, play_count: 10000 * (i + 1), like_count: 1000 * (i + 1), comment_count: 100 * (i + 1), share_count: 50 * (i + 1), url: searchUrl, tags: [keyword, '热门'], publish_time: new Date().toISOString().split('T')[0] ...[truncated 1902 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Implement genuine extraction of required fields from the loaded page or an authorized API. 2. Validate extracted records against expected schemas and reject incomplete or unverified results. 3. If the project is intentionally a demonstration, rename it accordingly and clearly identify every generated record as synthetic. 4. Add an explicit field such as: ```json { "data_source": "synthetic", "is_mock": true } ``` 5. Never silently fall back to mock data. Require an explicit `--mock` option and print a prominent warning to both standard error and output files. 6. Return a nonzero exit status when real scraping fails unless mock mode was deliberately selected. 7. Avoid opening a browser when producing synthetic examples. 8. Add tests proving that production mode returns values extracted from the page rather than deterministic placeholders. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (21)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill presents itself as retrieving real Douyin videos, copy, and hot-list data, but the finding indicates it may return locally constructed placeholder results instead of actual site content. In an agent setting, this is a trust and integrity problem: users may act on false data while believing the tool performed real external retrieval.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding
The skill presents itself as retrieving real Douyin videos, copy, and hot-list data, but the finding indicates it may return locally constructed placeholder results instead of actual site content. In an agent setting, this is a trust and integrity problem: users may act on false data while believing the tool performed real external retrieval.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill presents itself as retrieving real Douyin videos, copy, and hot-list data, but the finding indicates it may return locally constructed placeholder results instead of actual site content. In an agent setting, this is a trust and integrity problem: users may act on false data while believing the tool performed real external retrieval.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
def mode_native() -> None:
    env = os.environ.copy()
    env.setdefault("PLAYWRIGHT_DOWNLOAD_HOST", "https://npmmirror.com/mirrors/playwright")
    env.setdefault("PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST", "https://cdn.npmmirror.com/binaries/chrome-for-testing")
    venv_python = Path("venv/bin/python")
Confidence
60% confidence
Finding
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The function is ներկայացված as scraping Douyin search results, but it returns fabricated placeholder records derived from the input keyword rather than data extracted from the page. This is dangerous because downstream users or agents may trust the output as real external evidence, enabling misinformation, bad business decisions, or deceptive automation.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The hot-list feature claims to fetch Douyin hot rankings but instead generates fake ranked entries locally. In an agent skill, this can mislead users into believing current trend data was retrieved from Douyin when no such verification occurred, making the deception operationally significant.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The skill advertises live Douyin scraping, but the implementation merely attempts to open a page and then always returns fabricated mock data. In an agent setting, this can mislead downstream users or systems into treating invented content as real external intelligence, causing integrity failures, bad decisions, and possible trust abuse.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The skill title and all user-facing instructions in this README are presented only in Chinese, with no indication that users may choose another language or that the skill is intentionally limited to a Chinese-speaking or region-specific audience. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill documentation instructs execution of a Python script and explicitly supports saving output to local files, but it declares no tool scope or permissions. That creates an authorization gap where a caller may invoke shell and file-write behavior that is not transparently declared or constrained, increasing the risk of unintended command execution or filesystem modification.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The trigger conditions are very broad and overlap with ordinary requests about Douyin content, which can cause unintended invocation of this skill in contexts where the user did not explicitly ask for scraping or shell-backed operations. Because the skill can execute scripts and write files, overly permissive triggering increases the chance of unnecessary network activity, local changes, or user confusion.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run(cmd: list[str], cwd: str | None = None, env: dict[str, str] | None = None) -> None:
    print("\n>>>", " ".join(cmd))
    subprocess.run(cmd, cwd=cwd, env=env, check=True)


def mode_official() -> None:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The manifest describes a skill for searching Douyin videos, hot lists, and related content, but this file implements local environment provisioning: pulling Docker images, building a custom image, creating a Python venv, and installing Playwright/Chromium. Those are developer/setup capabilities rather than user-justified scraping functionality, and they are not part of the declared natural-language skill purpose.

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Content
browser.close()
            return True
        except Exception as exc:
            print(f"[douyin-scraper] 浏览器不可用,使用模拟数据: {exc}", file=__import__("sys").stderr)
            return False

    def search(self, keyword: str, limit: int) -> list[VideoData]:
Confidence
75% confidence
Finding
Dynamic __import__() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
This shell script contains natural-language strings and comments exclusively in Chinese, including installation status, errors, and usage guidance. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is clearly justified, which is not present here.

Missing User Warnings

Low
Confidence
82% confidence
Finding
This code pulls a remote Docker image, builds a local image, and writes a Dockerfile to disk. Although executed commands are printed, there is no user-facing warning or explanatory comment/docstring disclosing that the script will modify the local workspace and interact with Docker/network resources.

Missing User Warnings

Low
Confidence
88% confidence
Finding
The native mode creates a local virtual environment, installs dependencies, and downloads a Chromium browser binary, which changes the filesystem and fetches remote content. The script prints commands as they run, but it does not clearly warn users beforehand about these side effects.

Unpinned Dependencies

Low
Category
Supply Chain
Content
playwright>=1.40.0
Confidence
95% confidence
Finding
The dependency is specified with a lower-bound constraint only, which allows installation of any newer Playwright release, including unreviewed major or minor versions. This can introduce supply-chain risk, build instability, or accidental adoption of a vulnerable or breaking upstream release, especially in an automation/scraping skill that depends on browser-driving behavior.

Missing User Warnings

Low
Confidence
94% confidence
Finding
This code initiates HTTP navigation to Douyin using Playwright, which transmits the user's search terms and browser-like metadata to an external service. While the script logs the target URL, it does not warn the user that running the command will contact a third-party site and send query data off the local system.

Missing User Warnings

Low
Confidence
89% confidence
Finding
The script saves scraped results to arbitrary file paths provided on the command line, which modifies local files and could overwrite existing data. Although it logs after saving, there is no prior disclosure or confirmation that the operation will write to disk.

Static analysis

No suspicious patterns detected.