Back to skill

Security audit

Clawhub Gate

Security checks for vulnerabilities and agentic risk

Overview

This skill is a plausible ClawHub release helper, but its script can publish or update a skill before the promised security gate completes and has a code-injection flaw in its polling path.

Review before installing or using this as a release gate. Do not rely on `--local-only` to avoid network or publication, and do not treat this as a true pre-publish blocker unless the sync order, rollback behavior, slug handling, and dependency installation guidance are fixed.

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)

T09 · Insecure Skill Coding Practices

Error
Location
references/clawhub_gate.sh:288
Finding
Local-only mode still publishes the target Skill<![CDATA[ ## Vulnerability Details **File Location**: `references/clawhub_gate.sh:288-293` **Vulnerability Type**: `T09: Insecure Skill Coding Practices` **Risk Level**: High ### Vulnerable Code ```bash # Phase 2: sync run_sync # Phase 3: ClawScan if [[ "$LOCAL_ONLY" == "true" ]]; then log "Skipping ClawScan (--local-only)" log "Gate PASSED (local only)" exit 0 fi ``` The documented behavior in `SKILL.md` states that `--local-only` performs a quick local analysis without requiring network access. However, `run_sync` is called before `LOCAL_ONLY` is evaluated. `run_sync` invokes: ```bash clawhub sync ``` Consequently, local-only mode still creates or updates a remote ClawHub version. The option only skips subsequent ClawScan polling. ### Technical Analysis This is a control-flow defect that violates the principle of least surprise and the declared network boundary. A user explicitly selecting an offline operation does not provide informed authorization to publish the contents of `SKILL_DIR`. The upload is not necessary for the declared local-analysis functionality and therefore exceeds the minimum privileges and side effects required for that mode. ### Attack Path 1. A user receives or prepares a Skill that should only be inspected locally. 2. The user runs the documented command with `--local-only`. 3. Local static analysis succeeds. 4. The script executes `clawhub sync` using the user's authenticated ClawHub session. 5. Files in the target Skill directory are uploaded or an existing remote version is updated. 6. The script then reports `Gate PASSED (local only)`, concealing the fact that publication already occurred. ### Impact Assessment The vulnerability can cause unauthorized disclosure of source code, credentials accidentally stored in a Skill directory, internal URLs, proprietary instructions, or other unpublished content. It can also modify a public or organization-visible ClawHub package using the user's existing account permiss ...[truncated 168 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Evaluate `LOCAL_ONLY` immediately after static analysis and before any synchronization or network operation: ```bash if ! run_static_analysis; then fail "Gate FAILED at static analysis" exit 1 fi if [[ "$LOCAL_ONLY" == "true" ]]; then log "Gate PASSED (local only; no network operations performed)" exit 0 fi run_sync wait_for_clawscan "$slug" ``` Additional hardening should include: - Avoid reading the ClawHub token in local-only mode. - Verify that `clawhub`, Python network requests, and any other network-capable subprocesses cannot be invoked on the local-only path. - Add an automated test that replaces `clawhub` with a failing mock and confirms it is never called under `--local-only`. - Update status messages so they clearly distinguish local analysis from publication. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
references/clawhub_gate.sh:160
Finding
Directory-derived slug is interpolated into executable Python source<![CDATA[ ## Vulnerability Details **File Location**: `references/clawhub_gate.sh:160-171` **Vulnerability Type**: `T09: Insecure Skill Coding Practices` **Risk Level**: High ### Vulnerable Code The slug is derived from the user-controlled Skill directory name: ```bash local slug slug=$(basename "$SKILL_DIR") ``` It is then inserted directly into the source text passed to `python3 -c`: ```bash local result result=$(python3 -c " import urllib.request, json, os, glob # Read token from clawhub config config_path = os.path.expanduser('~/.config/clawhub/config.json') with open(config_path) as f: token = json.load(f).get('token', '') slug = '$slug' ``` ### Technical Analysis Shell quoting does not make interpolation into another programming language safe. The shell expands `$slug` before Python parses the resulting source. A directory basename containing a single quote and valid Python syntax can terminate the string literal and inject additional Python statements. The injected code executes after the Python process has opened the ClawHub configuration and loaded the token into memory. It runs with all filesystem, process, and network privileges of the user running the gate. This is a cross-language code-injection vulnerability: untrusted shell data is used to generate executable Python source instead of being passed through a data-only interface. ### Attack Path 1. An attacker creates or distributes a Skill in a directory whose basename contains a Python string terminator and injected Python statements. 2. The victim sets `SKILL_DIR` to that directory and runs the gate normally. 3. The script calculates the slug with `basename`, preserving the malicious characters. 4. Static analysis succeeds and the Skill is synchronized. 5. During ClawScan polling, the malicious basename is substituted into the `python3 -c` program. 6. Python parses and executes the injected statements with the victim's user privileges. 7. The injected code can read local files, la ...[truncated 919 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Never interpolate the slug into Python source. Pass it as a positional argument: ```bash result=$(python3 - "$slug" <<'PY' import json import os import sys import urllib.request slug = sys.argv[1] # Continue using slug strictly as data. PY ) ``` Alternatively, export it as an environment variable and retrieve it with `os.environ`. Also apply strict validation before constructing API paths: ```bash if [[ ! "$slug" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]]; then fail "Invalid ClawHub slug" exit 3 fi ``` Further hardening should include: - URL-encode path components with `urllib.parse.quote`. - Remove the unused `glob` import. - Keep Python source in a separate reviewed file rather than generating it in a shell string. - Add tests using directory names containing quotes, newlines, semicolons, Unicode characters, and shell metacharacters. - Ensure exceptions and subprocess output never print authentication headers or token values. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
references/clawhub_gate.sh:288
Finding
Remote security verdict is obtained only after public synchronization<![CDATA[ ## Vulnerability Details **File Location**: `references/clawhub_gate.sh:288-299` **Vulnerability Type**: `T09: Insecure Skill Coding Practices` **Risk Level**: High ### Vulnerable Code ```bash # Phase 2: sync run_sync # Phase 3: ClawScan if [[ "$LOCAL_ONLY" == "true" ]]; then log "Skipping ClawScan (--local-only)" log "Gate PASSED (local only)" exit 0 fi if ! wait_for_clawscan "$slug"; then exit 1 fi ``` The synchronization function performs publication before the remote verdict: ```bash run_sync() { echo "" log "=== Phase 2: Publishing to ClawHub ===" if ! clawhub sync 2>&1; then fail "clawhub sync failed" exit 1 fi log "clawhub sync: DONE" } ``` ### Technical Analysis The Skill is described as a pre-publish security gate, but its actual order is: 1. Run limited local checks. 2. Publish the Skill. 3. Wait for ClawScan. 4. Report failure if the published version is malicious or otherwise rejected. A failure after publication only changes the local exit status. The script contains no rollback, unpublish, quarantine, visibility restriction, or deletion operation. Therefore, a version rejected by ClawScan may remain remotely available after the gate has failed. This is a fail-open publication workflow. ShellCheck and Bandit cannot establish that an entire Skill is safe: they only analyze shell and Python code for selected patterns and do not cover instruction hijacking, non-Python payloads, embedded secrets, or broader semantic behavior. ### Attack Path 1. An attacker submits a harmful Skill that does not trigger the configured ShellCheck or Bandit thresholds. 2. A maintainer runs the purported pre-publish gate. 3. Local analysis passes. 4. `clawhub sync` creates or updates the remote version. 5. ClawScan later marks the version suspicious, malicious, or failed. 6. The script exits with an error but performs no rollback. 7. The rejected version can remain published and may be downloaded or e ...[truncated 873 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Use a true staged-release workflow: 1. Upload the candidate as private, draft, or quarantined. 2. Poll the security verdict for the exact uploaded version. 3. Promote that immutable version to public only after all mandatory checks pass. 4. Delete or retain rejected drafts with restricted visibility. If ClawHub does not support staging, the script should not claim to be a pre-publish gate. At minimum: - Capture the exact version returned by `clawhub sync`. - Poll that version rather than assuming `items[0]` is the uploaded version. - Automatically unpublish or quarantine it after malicious, failed, error, or timeout results. - Verify that rollback completed successfully. - Treat rollback failure as a critical incident and print the exact affected version. - Document the temporary exposure window explicitly. - Consider packaging and scanning locally before invoking any publication command. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:95
Finding
Documentation recommends unpinned installation into the system Python environment<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:95` **Vulnerability Type**: `T08: Insecure Dependencies` **Risk Level**: Medium ### Vulnerable Code ```bash pip install --break-system-packages bandit ``` ### Technical Analysis The installation instruction retrieves the latest available `bandit` package and its dependency graph without pinning versions or hashes. The `--break-system-packages` option bypasses protections intended to prevent `pip` from modifying a Python environment managed by the operating-system package manager. Although Bandit is a legitimate tool and no malicious dependency is identified in the reviewed files, the recommended installation method creates unnecessary supply-chain and environment-integrity risk. The effective installed code can change over time without any corresponding change to this Skill. ### Attack Path 1. A user follows the documented prerequisite command. 2. `pip` resolves the current mutable Bandit release and transitive dependencies from the configured package index. 3. Installation modifies the system-managed Python environment despite package-manager safeguards. 4. A compromised, substituted, or incompatible future package release executes installation code or affects later Python operations. 5. Conflicts can also break operating-system utilities or other applications sharing the same interpreter. ### Impact Assessment Package installation generally runs with the permissions of the invoking user and may be run with elevated privileges when users interpret the command as a system prerequisite. Potential impact includes: - Execution of compromised package installation or runtime code. - Modification of the shared system Python environment. - Dependency conflicts affecting unrelated applications. - Non-reproducible audit behavior caused by dependency version drift. There is no evidence in the reviewed project that a specific Bandit release is malicious; the finding concerns the unsafe dependency in ...[truncated 24 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Install dependencies in an isolated environment and pin reviewed versions: ```bash python3 -m venv .venv . .venv/bin/activate python -m pip install --require-hashes -r requirements.txt ``` The requirements file should contain exact versions and verified hashes for Bandit and all transitive dependencies. Additional controls should include: - Prefer a trusted operating-system package where suitable. - Do not recommend `sudo pip` or `--break-system-packages`. - Record the tested ShellCheck, Bandit, Python, `jq`, and ClawHub CLI versions. - Use a locked container image or reproducible environment for release gating. - Periodically review and deliberately update pinned dependencies rather than resolving mutable latest versions during installation. ]]>
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (9)

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill explicitly describes networked behavior: it reads a local auth token, invokes `clawhub sync`, and polls a remote ClawScan API, but it declares no `permissions` or `allowed-tools` scope. That mismatch weakens reviewability and can let a user invoke a skill with broader side effects than the manifest communicates, including publication actions and outbound requests.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger regexes are very broad and can match ordinary discussion of publishing, syncing, or security checks, causing the skill to activate outside narrowly intended contexts. Because this skill can run local analyzers, read config, make network calls, and trigger `clawhub sync` publication behavior, overmatching raises the risk of accidental side effects and unintended release operations.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The script’s advertised purpose is to block publication until VirusTotal and ClawScan checks pass, but `--local-only` exits successfully after local static analysis and skips the remote security gate entirely. In a pre-publish security skill, this creates a real policy-bypass path: users or automation can publish without the very checks the skill claims to enforce.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The natural-language instructions and trigger phrases are Chinese-only, which effectively imposes a language constraint on users. The file does not indicate that this is an intentional region-specific skill or provide an opt-in language/locale choice.

Natural-Language Policy Violations

Low
Confidence
94% confidence
Finding
This shell script includes user-facing natural-language comments and usage guidance in Chinese only, such as the location and usage lines. Under the language/locale policy, forcing a specific language without offering a choice or documenting a justified locale constraint is a policy concern.

Intent-Code Divergence

Low
Confidence
81% confidence
Finding
The log/documentation for Phase 2 explicitly states `Publishing to ClawHub`, which communicates a concrete publish action. The code actually runs `clawhub sync`, and elsewhere the manifest/triggers distinguish sync from publish, so this inline documentation overstates what the step does.

Static analysis

No suspicious patterns detected.