Back to skill

Security audit

Clawhub Smart Updater

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a legitimate updater, but it can automatically rewrite installed skills with unsafe validation and overstated safety claims, so users should review it carefully before use.

Install only if you are prepared to run it manually in dry-run mode first, review every proposed change to SKILL.md, JSON, scripts, and dependencies, avoid --force and unattended cron use, and disable automatic safe updates until slug validation, shell=False command execution, baseline-aware diffing, and the documented security checks are actually implemented.

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

T09 · Insecure Skill Coding Practices

Error
Location
smart-update.py:74
Finding

Shell Command Injection and Path Traversal Through Unvalidated Skill Slugs

Content
View full analysis

Vulnerability Details

File Location: smart-update.py:74-83, smart-update.py:102-105, smart-update.py:140-152
Vulnerability Type: Shell command injection and unsafe path construction
Risk Level: High

Vulnerable Code

python
def run_command(self, cmd: str) -> Tuple[bool, str]:
    """Run shell command and return success status and output."""
    try:
        result = subprocess.run(
            cmd,
            shell=True,
            capture_output=True,
            text=True,
            timeout=60
        )
        return result.returncode == 0, result.stdout + result.stderr
    except Exception as e:
        return False, str(e)
python
def get_latest_version(self, slug: str) -> Optional[str]:
    """Get latest version of a skill from ClawHub."""
    success, output = self.run_command(f"clawhub inspect {slug}")
    if not success:
        return None
python
def download_new_version(self, slug: str) -> Optional[str]:
    """Download new version of skill to temp directory."""
    temp_slug_dir = os.path.join(self.temp_dir, f"{slug}-new")

    if os.path.exists(temp_slug_dir):
        shutil.rmtree(temp_slug_dir)
    os.makedirs(temp_slug_dir)

    success, output = self.run_command(
        f"clawhub inspect {slug} --files --output \"{temp_slug_dir}\""
    )

Technical Analysis

Skill slugs parsed from clawhub list are inserted directly into command strings passed to subprocess.run with shell=True. No strict character validation, escaping, or argument-array invocation is used.

If an attacker can cause a crafted slug containing shell metacharacters to appear in the installed-skill listing, the shell interprets those characters as command syntax rather than as part of a literal skill identifier. Quoting only the output path does not protect the unquoted slug in clawhub inspect {slug}.

The same slug is also passed to `os.pa ...[truncated 1843 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove shell=True and pass commands as argument arrays:

    python
    subprocess.run(
        ["clawhub", "inspect", slug],
        shell=False,
        capture_output=True,
        text=True,
        timeout=60,
        check=False,
    )
    
  2. Apply a strict allowlist to every slug before using it in commands or paths:

    python
    import re
    
    if not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9._-]*", slug):
        raise ValueError("Invalid skill slug")
    
  3. Resolve every generated path and verify that it remains beneath its intended parent directory using Path.resolve() and Path.relative_to().

  4. Reject absolute paths, .. components, path separators, control characters, and shell metacharacters.

  5. Avoid accepting security-sensitive identifiers from loosely parsed human-readable CLI output. Prefer a structured JSON output mode if the ClawHub CLI supports one.

  6. Run scheduled updates under a dedicated, minimally privileged account with access limited to the required workspace.

T09 · Insecure Skill Coding Practices

Error
Location
smart-update.py:186
Finding

Untrusted Files Are Automatically Classified as Safe and Overwritten

Content
View full analysis

Vulnerability Details

File Location: smart-update.py:186-214, smart-update.py:394-403
Vulnerability Type: Unsafe update classification and automatic overwrite of trusted skill content
Risk Level: High

Vulnerable Code

python
if comparison["identical"]:
    continue  # No change

# Categorize based on file type
if rel_path.endswith(('.md', '.txt', '.json')):
    # Documentation and configs are usually safe
    safe_files.append({
        "file": rel_path,
        "type": "documentation",
        "reason": "Non-code file"
    })
elif rel_path.endswith('.py'):
    # Code files need review if modified locally
    if comparison["locally_modified"]:
        conflict_files.append({
            "file": rel_path,
            "type": "code",
            "reason": "Both upstream and local modified this file",
            "old_hash": comparison["hash_old"],
            "new_hash": comparison["hash_new"]
        })
    else:
        safe_files.append({
            "file": rel_path,
            "type": "code",
            "reason": "Upstream only change"
        })
else:
    # Other files
    safe_files.append({
        "file": rel_path,
        "type": "other",
        "reason": "Non-code file"
    })
python
if self.config["update"]["auto_apply_safe"]:
    print(f"  Applying {len(changes['safe'])} safe changes...")
    # Copy safe files
    for file_info in changes["safe"]:
        src = os.path.join(new_dir, file_info["file"])
        dst = os.path.join(old_dir, file_info["file"])
        os.makedirs(os.path.dirname(dst), exist_ok=True)
        shutil.copy2(src, dst)

Technical Analysis

The updater treats all changed Markdown, text, JSON, and unknown-extension files as safe. It then copies these files into the installed skill without security review. This classification is unsafe because file extensions do not establish that conte ...[truncated 2224 chars]

Remediation
View remediation

Remediation Suggestions

  1. Default every changed or newly introduced file to manual review rather than treating broad extensions as safe.
  2. Always classify instruction files, manifests, configuration files, dependency files, scripts, binaries, symlinks, and executable formats as security-sensitive.
  3. Maintain authenticated hashes for the previously installed upstream version and perform a genuine three-way comparison:
    • Previous trusted upstream version
    • Current local version
    • New upstream version
  4. Verify update signatures, publisher identity, package integrity, and expected version metadata before copying any files.
  5. Require explicit approval for newly added files and for changes that alter dependencies, permissions, instructions, executable content, or network destinations.
  6. Detect and report upstream file deletions rather than silently retaining obsolete files.
  7. Stage the entire update in an isolated directory and present a complete diff before atomic installation.
  8. Disable auto_apply_safe by default until the classification logic and integrity verification are robust.
  9. Treat symlinks specially and reject paths that resolve outside the staging or destination directory.

T09 · Insecure Skill Coding Practices

Warning
Location
README.md:152
Finding

Documentation Claims Security Controls That Are Not Implemented

Content
View full analysis

Vulnerability Details

File Location: README.md:152-155, SKILL.md:234-237
Vulnerability Type: Misrepresentation of update security controls
Risk Level: Medium

Vulnerable Documentation

markdown
### Security Checks
- **VirusTotal integration**: Warns about SUSPICIOUS flagged skills
- **Dependency audit**: Checks for new dependencies in updates
- **Permission review**: Alerts on new file permissions

The same unsupported claims appear in SKILL.md:

markdown
### Security
- VirusTotal integration (warns on SUSPICIOUS)
- Dependency change detection
- Permission audit
- No blind overwrites

Technical Analysis

The executable implementation contains no VirusTotal integration, dependency-change analysis, permission audit, publisher-signature verification, or equivalent security gate. Nevertheless, the documentation presents these controls as active safety features.

This creates a security-relevant false assurance because the updater defaults to automatically applying files classified as safe. Users may reasonably rely on the claimed scanning and permission checks when deciding to enable unattended scheduled updates.

The claim that the updater performs no blind overwrites is also inconsistent with its behavior: Markdown, JSON, text, and unknown file types are copied over installed files based primarily on their extensions.

Attack Path

  1. A user reads the documented security guarantees and concludes that updates are checked for malicious indicators, dependency changes, and permission changes.
  2. Based on those assurances, the user leaves auto_apply_safe enabled and configures the documented weekly scheduled execution.
  3. An upstream release introduces malicious instructions, configuration, dependencies, or executable content.
  4. The updater performs none of the advertised security checks.
  5. The unsafe-classification logic automatically installs eligible files. 6 ...[truncated 510 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove all claims for controls that are not implemented.
  2. Clearly disclose that downloaded updates are not malware-scanned, dependency-audited, permission-audited, or cryptographically verified.
  3. If these controls are implemented later, make them fail closed and expose their results in the generated report before any files are copied.
  4. Add tests proving that each documented security control is invoked and blocks updates on failure.
  5. Keep automatic updates disabled by default until the documented protections exist.
  6. Correct other unsupported interface claims, including references to absent --report, --accept, --reject, --force-unlock, --ignore-whitespace, and --generate-diff options and the absent restore-backup.py file.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (11)

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 · SKILL.md (reported line 11)May include surrounding context.

md
Use this skill when:
- You have **locally modified skills** from ClawHub
- You want to update skills **without losing your changes**
- You need **conflict detection** and merge recommendations
- You want **automatic backups** before updates
- You prefer **safe, conservative updates** over risky auto-updates

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- `SKILL.md` - This documentation

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
99% confidence
Finding

This is a true tool-parameter abuse issue because the program feeds interpolated strings into a shell. The skill context increases risk: it processes package/skill identifiers and file paths related to updates, so a crafted slug or manipulated input could trigger arbitrary command execution during a trusted maintenance workflow.

Content

Scanner excerpt · smart-update.py (reported line 78)May include surrounding context.

python
def run_command(self, cmd: str) -> Tuple[bool, str]:
        """Run shell command and return success status and output."""
        try:
            result = subprocess.run(
                cmd,
                shell=True,
                capture_output=True,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README explicitly describes categories of changes that will be 'auto-apply' and 'applied automatically' without a prominent warning that running the updater can modify local files. In an updater skill, normalizing silent or semi-automatic file modification increases the chance users will run it without understanding that documentation and config changes may be written into their workspace, which can lead to unintended code or configuration drift.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README advertises a '--force' option as 'skip conflict detection' without an adjacent warning explaining that this bypass can overwrite local changes or apply unsafe upstream modifications unchecked. Because this skill is an updater that changes files on disk, documenting a dangerous override without strong cautions makes accidental destructive use substantially more likely.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The documentation describes running an updater that backs up, updates, and cleans up skill files, but it does not clearly warn users that executing it will modify local files and may create or delete backup data. This can lead to unintended self-modification and data retention/deletion effects, especially when used in automated contexts where users may not review side effects carefully.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The cron integration example sends update summaries over WhatsApp to a configured phone number without a clear privacy warning about what information may leave the local environment. Reports could disclose installed skills, filenames, conflict details, versions, or security warnings to third-party messaging infrastructure, creating avoidable data exposure.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module docstring promises it 'Detects local modifications' and 'Preserves local changes', but the code only compares the current installed file to the newly downloaded version in compare_files/categorize_changes. Because it lacks a baseline for the prior upstream version, any upstream-only code change in a .py file is labeled 'locally_modified', so the documented intent of detecting true local modifications is contradicted by the actual logic.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
98% confidence
Finding

The helper executes arbitrary shell strings with shell=True, which turns any unsanitized value interpolated into cmd into a shell injection sink. In this file, slug-derived commands such as 'clawhub inspect {slug}' and output-path commands are built as strings, so a malicious skill name or other attacker-controlled value could execute additional shell commands in the user's environment.

Content

Scanner excerpt · smart-update.py (reported line 78)May include surrounding context.

python
def run_command(self, cmd: str) -> Tuple[bool, str]:
        """Run shell command and return success status and output."""
        try:
            result = subprocess.run(
                cmd,
                shell=True,
                capture_output=True,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The CLI exposes a --force option that explicitly skips conflict detection, and the update path then copies files into the installed skill directory. Although status messages are printed, there is no confirmation prompt or explicit warning that using this option can overwrite locally modified files and bypass manual review.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The --cleanup-backups mode triggers shutil.rmtree deletion of backup directories, but the CLI help and surrounding messaging do not clearly warn that this permanently removes stored backups. The runtime prints which backups were cleaned only after deletion, which is not a prior disclosure of the destructive action.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.