Back to skill

Security audit

SkillMetricScraper

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches a trend-reporting purpose, but its default workflow uses high-impact Docker access and other broad side effects without clear upfront user consent.

Review before installing. Run only in a least-privileged environment without Docker daemon access unless you explicitly want it to copy metrics.db from openclaw-gateway-secure. Prefer --no-bridge and --skip-x for a narrower run, inspect or pin dependencies before pip install, and treat generated Markdown/JSON as untrusted because public skill and community content can influence the report.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
run_weekly.py:38
Finding

Default Cross-Container Database Access Violates Least Privilege

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
script_generator.py:79
Finding

Indirect Prompt Injection Through Untrusted Registry and Community Content

Content
View full analysis
str: track = skill.get("_track", "mover") track_label = "NEW THIS WEEK" if track == "rocket" else "TOP MOVER" cold = skill.get("_cold_start", False) template = USER_TEMPLATE_COLD if cold else USER_TEMPLATE_VELOCITY return template.format( display_name=skill.get("display_name", "Unknown"), author=skill.get("author", "Unknown"), summary=skill.get("summary") or "No description.", content=(skill.get("content") or "No documentation available.")[:3000], track=track_label, ) ``` ```python message = client.messages.create( model=model, max_tokens=150, system=SYSTEM_PROMPT, messages=[{"role": "user", "content": _build_prompt(skill)}], ) script = _strip_markdown(message.content[0].text) ``` X search output is handled similarly: ```python prompt = f"""Extract structured signals from this X/Twitter search summary about OpenClaw skills. For each tweet URL below, create a JSON object with: - "url": the tweet URL - "title": a short descriptive title (5-10 words) - "summary": one sentenc ...[truncated 3351 chars]
Remediation
View remediation
... ``` 4. Escape or encode delimiter characters so source content cannot prematurely close the data block. 5. Use separate prompt stages: - Deterministically extract factual fields. - Validate those fields. - Generate prose only from the validated representation. 6. Enforce strict response schemas using structured output support where available. 7. Validate every returned field: - Enumerated categories only. - Maximum lengths. - HTTPS URLs only. - Expected source domains where applicable. - No control characters or raw markup. 8. Reject output containing instruction-like phrases, unexpected calls to action, unrelated URLs, or unsupported claims. 9. Preserve source attribution and require generated claims to map to extracted evidence. 10. Do not pass generated reports into another tool-enabled Agent without sanitization and explicit untrusted-content handling. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
script_generator.py:229
Finding

Unescaped External Content Allows Markdown and Link Injection in Reports

Content
View full analysis
{r.get('summary', '')}" if r.get("summary") else "", "", "**YouTube Script**", "", f"_{r.get('script', '')}_", "", "---", "", ] ``` The new-skill renderer has the same issue: ```python lines += [ f"### [{r.get('display_name', r.get('slug', '?'))}]({r.get('clawhub_url', '')})", "", ( f"{author_str}" f"**Downloads:** {r.get('downloads', 0):,} | " f"**Installs:** {r.get('installs_current', 0):,} | " f"**Stars:** {r.get('stars', 0)} | " f"**Score:** {r.get('_score', 0.0):.4f}" f"{age}" ), "", f"> {r.get('summary', '')}" if r.get("summary") else "", "", "**YouTube Script**", "", f"_{r.get('script', '')}_", "", "---", "", ] ``` Community content is also rendered directly: ```python link = f"[{title}]({url})" if url else title tag_str = " ".join(f"`#{t}`" for t in tags) if tags else "" date_str = f" ({item_date})" if item_date else "" source_icon = SOURCE_ICON.get(source, "") source_prefix = f"{source_icon} " if source_icon else "" lines.append(f"- {source_prefix}**{link}**{date_str} ...[truncated 1966 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:48
Finding

Runtime Installation of Unpinned Third-Party Dependencies

Content
View full analysis
/dev/null || pip3 install -r requirements.txt --quiet ``` The requirements use unrestricted upper versions and no hashes: ```text httpx>=0.27.0 python-dotenv>=1.0.0 anthropic>=0.49.0 beautifulsoup4>=4.12.0 ``` ### Technical Analysis Each requirement specifies only a minimum version. A future invocation can therefore install a different dependency set from the one reviewed during this audit. No lockfile, exact versions, artifact hashes, or trusted-index restriction is provided. Python package installation and import can execute package-controlled code with the privileges of the invoking Agent. Consequently, compromise of the configured package index, a dependency account, or a future permitted release can alter the effective code executed by the Skill without any repository change. The first installation attempt redirects standard error to `/dev/null`, reducing visibility into certificate, resolver, repository, or package warnings. Falling back from `pip` to `pip3` can also produce inconsistent environments. This is a supply-chain exposure rather than evidence that any currently named dependency is malicious. ### Attack Path 1. A user invokes the Skill in an environment where dependencies are not already installed. 2. The Agent follows `SKILL.md` and runs the installation command. 3. `pip` resolves any version greater than or equal to the stated minimum. 4. A compromised package release, dependency, account, or configured index supplies altered code. 5. Package-controlled code runs during installation or when imported. 6. That code inherits the Agent process's filesystem, network, environm ...[truncated 657 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (50)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

Using an external X/Twitter search path, extracting tweet URLs, invoking an LLM to structure content, and writing weekly signal files is a materially broader workflow than the declared ClawHub trend/script role. This increases attack surface through additional network sources and untrusted content ingestion while concealing the actual operational behavior from users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

Using an external X/Twitter search path, extracting tweet URLs, invoking an LLM to structure content, and writing weekly signal files is a materially broader workflow than the declared ClawHub trend/script role. This increases attack surface through additional network sources and untrusted content ingestion while concealing the actual operational behavior from users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

Using an external X/Twitter search path, extracting tweet URLs, invoking an LLM to structure content, and writing weekly signal files is a materially broader workflow than the declared ClawHub trend/script role. This increases attack surface through additional network sources and untrusted content ingestion while concealing the actual operational behavior from users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

Using an external X/Twitter search path, extracting tweet URLs, invoking an LLM to structure content, and writing weekly signal files is a materially broader workflow than the declared ClawHub trend/script role. This increases attack surface through additional network sources and untrusted content ingestion while concealing the actual operational behavior from users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Using an external X/Twitter search path, extracting tweet URLs, invoking an LLM to structure content, and writing weekly signal files is a materially broader workflow than the declared ClawHub trend/script role. This increases attack surface through additional network sources and untrusted content ingestion while concealing the actual operational behavior from users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Using an external X/Twitter search path, extracting tweet URLs, invoking an LLM to structure content, and writing weekly signal files is a materially broader workflow than the declared ClawHub trend/script role. This increases attack surface through additional network sources and untrusted content ingestion while concealing the actual operational behavior from users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

Using an external X/Twitter search path, extracting tweet URLs, invoking an LLM to structure content, and writing weekly signal files is a materially broader workflow than the declared ClawHub trend/script role. This increases attack surface through additional network sources and untrusted content ingestion while concealing the actual operational behavior from users.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Using an external X/Twitter search path, extracting tweet URLs, invoking an LLM to structure content, and writing weekly signal files is a materially broader workflow than the declared ClawHub trend/script role. This increases attack surface through additional network sources and untrusted content ingestion while concealing the actual operational behavior from users.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest describes a skill focused on ClawHub skills ranking and script generation, but this file is dedicated to collecting GitHub metadata for core OpenClaw repositories such as openclaw/openclaw and openclaw/clawhub. Tracking repo stars, forks, releases, PRs, and commit activity for ecosystem repositories is a materially different function from analyzing trending skills or producing video-script content.

Content

No source excerpt is available for this finding.

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

Scanner excerpt · storage.py (reported line 70)May include surrounding context.

python
def upsert_skills(skills: list[dict]) -> None:
    """Insert or update skill metadata (does not touch metrics_history)."""
    with _connect() as conn:
        conn.executemany(
            """

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · x_capture.py (reported line 16)May include surrounding context.

python
Requires:
    - x-search skill at ~/.claude/skills/x-search/scripts/x_search.py
    - XAI_API_KEY in env or .env file
    - ANTHROPIC_API_KEY in .env (for LLM structuring step)
"""

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · x_capture.py (reported line 17)May include surrounding context.

python
Requires:
    - x-search skill at ~/.claude/skills/x-search/scripts/x_search.py
    - XAI_API_KEY in env or .env file
    - ANTHROPIC_API_KEY in .env (for LLM structuring step)
"""

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill declares executable behavior that uses environment variables, filesystem access, network access, and shell commands, but does not declare an explicit tool scope such as permissions or allowed-tools. That omission weakens reviewability and can cause the agent to invoke capabilities the user did not clearly consent to, especially since the skill also installs dependencies and writes persistent local data.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

When the manifest description omits social-signal capture and project tracking capabilities, users and reviewers lose a reliable summary of what the skill actually does. This is dangerous because manifest metadata is often the first or only trust signal used to decide whether to invoke a skill.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Overly broad trigger phrases can cause accidental invocation of a skill with network, shell, and file-write behavior in response to common user language. In this context, the risk is amplified because the skill performs dependency installation and persistent local writes, so unintended activation can have real side effects.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill instructs dependency installation and execution of commands that create a database and output files without prominently warning about those host modifications. That is a real safety issue because users may authorize what sounds like report generation without understanding that packages will be installed and persistent state will be created locally.

Content

No source excerpt is available for this finding.

Tainted flow: 'url' from httpx.get (line 81, network input) → httpx.get (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · harvester.py (reported line 27)May include surrounding context.

python
return {"content": "", "author": ""}
    url = f"{CLAWHUB_BASE}/api/v1/skills/{slug}"
    try:
        resp = httpx.get(url, timeout=REQUEST_TIMEOUT, follow_redirects=True,
                         headers={"Accept": "application/json"})
        if resp.status_code != 200:
            return {"content": "", "author": ""}

Tainted flow: 'owner' from httpx.get (line 34, network input) → httpx.get (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · harvester.py (reported line 71)May include surrounding context.

python
# Get default branch
    try:
        api_resp = httpx.get(
            f"https://api.github.com/repos/{owner}/{repo}",
            headers={**headers, "Accept": "application/vnd.github+json"},
            timeout=REQUEST_TIMEOUT,

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · harvester.py (reported line 72)May include surrounding context.

python
# Get default branch
    try:
        api_resp = httpx.get(
            f"https://api.github.com/repos/{owner}/{repo}",
            headers={**headers, "Accept": "application/vnd.github+json"},
            timeout=REQUEST_TIMEOUT,
        )

Tainted flow: 'url' from httpx.get (line 81, network input) → httpx.get (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · harvester.py (reported line 83)May include surrounding context.

python
for filename in README_CANDIDATES:
        url = f"{GITHUB_RAW}/{owner}/{repo}/{branch}/{filename}"
        try:
            resp = httpx.get(url, headers=headers, timeout=REQUEST_TIMEOUT)
            if resp.status_code == 200:
                return resp.text[:MAX_CONTENT_CHARS]
        except Exception:

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest describes a skill focused on tracking trending ClawHub skills and generating weekly YouTube-style ranking scripts. This file instead runs an hourly heartbeat that snapshots the top 500 skills into storage and also captures OpenClaw ecosystem GitHub repository metadata, which is broader operational data collection than the stated weekly ranking/script-generation behavior.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The docstring explicitly claims "Append-only inserts — no dedup destruction of earlier hourly rows," suggesting non-mutating storage behavior. However, the code later calls storage.upsert_skills(skills), which by definition updates existing records and is not purely append-only, creating a direct contradiction between documentation and implementation intent.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger list contains broad phrases such as "skills weekly", "trending skills", and "weekly report" that can overlap with ordinary user intent and cause the skill to activate unexpectedly. Because this skill performs network access and writes persistent data, accidental invocation can lead to unintended external requests and local data collection without the user realizing this specific skill was selected.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill explicitly documents persistent SQLite/JSON storage and community research using web searches, but does not present an upfront warning that using it will perform external network access and retain collected data on disk. In context, this increases privacy and transparency risk because a user may ask for trending information and unknowingly trigger collection, storage, and ongoing snapshot accumulation.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · project_tracker.py (reported line 27)May include surrounding context.

python
def _gh_api(endpoint: str) -> dict | list | None:
    """Call GitHub API via gh CLI. Returns parsed JSON or None on error."""
    try:
        result = subprocess.run(
            ["gh", "api", endpoint],
            capture_output=True, text=True, timeout=15, encoding="utf-8",
        )

Static analysis

No suspicious patterns detected.