Back to skill

Security audit

Sentiment Radar

Security checks for vulnerabilities and agentic risk

Overview

The skill has a plausible sentiment-analysis purpose, but it includes under-scoped browser scraping and an unsafe external config rewrite that could run injected code.

Install only after review. Use a sandboxed environment and an ephemeral browser profile, pin and inspect MediaCrawler before running it, avoid untrusted keyword input, do not expose personal browser sessions or OAuth tokens unnecessarily, and define retention/redaction rules for collected social-media data.

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)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/xhs_crawler.py:37
Finding
Arbitrary Python Code Execution Through Keyword Configuration Injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/xhs_crawler.py`, lines 37–41; execution sink at lines 75–81 **Vulnerability Type**: Python source-code injection **Risk Level**: High ### Vulnerable Code ```python content = re.sub( r'KEYWORDS\s*=\s*"[^"]*"', f'KEYWORDS = "{keywords}"', content ) ``` The generated configuration is subsequently used when MediaCrawler is launched: ```python result = subprocess.run( [str(venv_python), "main.py", "--platform", "xhs", "--lt", "qrcode"], cwd=str(crawler_path), env=env, timeout=600, ) ``` ### Technical Analysis The value supplied through the `--keywords` command-line argument is interpolated directly into the source code of MediaCrawler's `config/base_config.py`. The value is not escaped or serialized as a valid Python string literal. An attacker can include quotation marks, statement delimiters, newlines, or comments in the keyword value. This allows the attacker to terminate the intended `KEYWORDS` string and inject additional Python statements. For example, a keyword value structurally equivalent to the following would produce executable Python code: ```text "; __import__('os').system('id'); # ``` The resulting configuration would contain code equivalent to: ```python KEYWORDS = ""; __import__('os').system('id'); #" ``` When MediaCrawler loads its Python configuration during startup, the injected statement can execute with the privileges of the user running the crawler. Using an argument list in `subprocess.run()` prevents shell injection at that particular call, but it does not mitigate the earlier Python source-code injection. ### Attack Path 1. The attacker causes the Skill to run `scripts/xhs_crawler.py` with a crafted `--keywords` value. 2. `update_config()` embeds the unescaped value into `config/base_config.py`. 3. The malicious value terminates the intended Python string and adds an arbitrary Python statement. 4. `run_crawler()` launches MediaCrawler usin ...[truncated 894 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Do not modify executable Python source with user-controlled text. 1. Store keywords in a data-only format such as JSON: ```python keywords_file.write_text( json.dumps({"keywords": keywords}, ensure_ascii=False), encoding="utf-8", ) ``` 2. Update MediaCrawler through a supported command-line option, environment variable, or structured configuration mechanism. 3. Validate that keywords are strings and enforce reasonable length and count limits. 4. If source modification is unavoidable, serialize the value with `repr(keywords)` rather than manually surrounding it with quotation marks: ```python replacement = f"KEYWORDS = {keywords!r}" ``` 5. Prefer an AST-aware configuration editor and validate the resulting file with `ast.parse()` before running MediaCrawler. 6. Write changes atomically and restore the original configuration after the crawl. 7. Run the crawler in a restricted environment with minimal filesystem and credential access. 8. Add regression tests using quotation marks, backslashes, newlines, comments, and statement delimiters in keyword input. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:23
Finding
Execution of an Unpinned External MediaCrawler Dependency<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 23–25 **Vulnerability Type**: Unpinned third-party dependency and mutable supply-chain source **Risk Level**: Medium ### Vulnerable Code ```bash git clone https://github.com/NanmiCoder/MediaCrawler ~/.openclaw/workspace/skills/media-crawler cd ~/.openclaw/workspace/skills/media-crawler uv sync ``` ### Technical Analysis The installation instructions clone the mutable default branch of an external Git repository without selecting a reviewed commit hash or verifying its integrity. They then install the repository's dependency environment with `uv sync`. Consequently, the code installed by these commands can differ from the code reviewed when this Skill was published. The external MediaCrawler source and its dependency graph are outside the audited project artifact. If the upstream repository, release process, maintainer account, or dependency chain is compromised, malicious code could be introduced after this Skill has already passed review. The project later executes the external installation through: ```python result = subprocess.run( [str(venv_python), "main.py", "--platform", "xhs", "--lt", "qrcode"], cwd=str(crawler_path), env=env, timeout=600, ) ``` This makes the unreviewed external component part of the Skill's effective execution path. ### Attack Path 1. A user follows the documented prerequisite instructions. 2. Git downloads the current state of MediaCrawler's mutable default branch. 3. `uv sync` resolves and installs the external project's dependencies. 4. An attacker-controlled upstream revision or compromised dependency is placed in the local MediaCrawler environment. 5. The user runs `scripts/xhs_crawler.py`. 6. The Skill launches the external `main.py` with the user's privileges. 7. Malicious upstream code can access resources available to that process. This attack path requires compromise or malicious modification of an external source; no evidence w ...[truncated 681 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin MediaCrawler to a specific reviewed commit or cryptographically signed release: ```bash git clone https://github.com/NanmiCoder/MediaCrawler ~/.openclaw/workspace/skills/media-crawler cd ~/.openclaw/workspace/skills/media-crawler git checkout --detach <reviewed-commit-hash> ``` 2. Publish the expected commit hash and verify it before installation. 3. Pin transitive Python dependencies with a committed lockfile containing integrity hashes. 4. Require signature or checksum verification for downloaded components. 5. Review the pinned MediaCrawler source and its installation hooks before execution. 6. Prevent automatic updates to an unreviewed branch. 7. Run the external crawler in a sandbox or container with narrowly scoped filesystem, browser, and network access. 8. Document a controlled upgrade process requiring review before changing the pinned revision. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
Findings (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding
The code partially matches the declared reporting goal: it does generate a structured sentiment-style report with keyword heat, product mention counts, pricing-related comment samples, comparison comment samples, and top-note summaries. However, the declared purpose emphasizes a multi-platform monitoring/analysis capability spanning XHS plus Twitter/Reddit, while the actual code only analyzes local JSON files corresponding to XHS crawl outputs. There is no evidence of English-platform support, social data collection, MCP integration, or broader cross-platform market intelligence workflows. Because the description materially overstates the scope and primary capability of the supplied code chunk, this is a mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description presents a broader sentiment-monitoring and analysis tool spanning XHS, Twitter, and Reddit, with structured reporting and insight generation. The supplied code instead implements a very specific Douyin video-search scraper. Its primary function is DOM extraction of search result cards via Playwright automation, followed by saving raw output. There is no sentiment classification, opinion aggregation, pricing complaint detection, comparison analysis, or report generation. The platform is also materially different: Douyin is not listed in the description, while the described platforms and collection methods (MediaCrawler for XHS, Xpoz MCP for Twitter/Reddit) do not appear in the code. This is a clear description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description presents a broad sentiment intelligence skill covering Chinese and English platforms plus downstream analysis and reporting. The supplied code chunk only supports a narrow subset: crawling Xiaohongshu data via MediaCrawler and exporting JSON. While XHS collection is consistent with one part of the description, the primary described capabilities—cross-platform monitoring and sentiment/report analysis—are absent from this code. This is a material description-to-behavior mismatch rather than a mere partial implementation detail.

Context-Inappropriate Capability

High
Confidence
94% confidence
Finding
The script explicitly uses browser automation to 'bypass API-level blocking' by attaching to a local Chrome instance over CDP and scraping a site through an interactive browser session. In an agent skill, this creates a risky capability expansion beyond ordinary sentiment analysis because it can leverage an authenticated/local browser context to access or extract data in ways not transparently declared, increasing the chance of misuse, policy evasion, and unintended data collection.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
print("ERROR: MediaCrawler venv not found. Run 'uv sync' in media-crawler/ first.")
        sys.exit(1)

    env = os.environ.copy()
    env["MPLBACKEND"] = "Agg"
    if "/usr/sbin" not in env.get("PATH", ""):
        env["PATH"] = f"/usr/sbin:{env['PATH']}"
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.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill instructs cloning repositories, reading tokens from the user's home directory, editing config files, running shell commands, and writing output files, but it declares no tool scope or permissions boundaries. That mismatch is dangerous because an agent or user may grant broader filesystem, environment, and shell access than expected, increasing the chance of unintended data exposure or command execution.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill instructs collection, storage, and analysis of social-media posts and comments, including output to local JSON and reports, but provides no privacy, retention, consent, or sensitive-data-handling guidance. That omission is dangerous because social content can contain personal data, account identifiers, and sensitive opinions, and users may unknowingly create local datasets or reports that violate policy, law, or internal handling requirements.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The skill explicitly recommends CDP browser use 'for anti-detection' and QR-login-based crawling, which normalizes evasion of platform defenses and may induce users or agents to automate authenticated sessions in ways that violate safeguards. In a sentiment-analysis context, that guidance is riskier because the stated purpose does not require stealth or bypass-oriented operational advice, yet it encourages techniques that can capture session context and broaden account-exposure risk.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The template hardcodes Chinese section titles and report wording, which imposes a specific language/locale on the generated report. Under the policy, locale constraints should either be optional for the user or clearly documented as justified for a region-specific use case.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The manifest describes sentiment monitoring on Chinese platforms via 小红书/XHS and English platforms via Twitter/Reddit, but this file is explicitly a Douyin scraper and collects raw video search data from douyin.com. That expands the implemented platform coverage beyond what the skill claims to support.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The script edits base_config.py inside an external MediaCrawler installation in place, which creates side effects outside the skill's own workspace and changes future behavior of that tool. Because it rewrites executable Python config text using unescaped user-supplied keywords, it can also corrupt the external installation or inject unintended content into the config file.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The script silently rewrites files in an external dependency without prominently informing the user that persistent changes will be made. In a skill context, this is risky because users may expect a read-only analysis tool, while the script alters another project's configuration and potentially affects later runs or other workflows.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
The script launches a separate Python interpreter from an external repository and executes its main.py with inherited environment variables. This creates a trust boundary issue: if the MediaCrawler checkout is malicious, compromised, or replaced via MEDIA_CRAWLER_PATH, the skill will run arbitrary code under the user's privileges.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
print("Starting XHS crawler (CDP mode)...")
    print("If login required, scan QR code on your phone.")
    result = subprocess.run(
        [str(venv_python), "main.py", "--platform", "xhs", "--lt", "qrcode"],
        cwd=str(crawler_path),
        env=env,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.