Back to skill

Security audit

Skill Install Guardian

Security checks for vulnerabilities and agentic risk

Overview

This security-checking skill is not clearly malicious, but its own checks can miss or misreport risky skills and it relies on unpinned npx execution.

Install only after review. Treat this as a helper, not a reliable gate: pin or preinstall a trusted ClawHub CLI, run it in a low-privilege environment, manually inspect upstream security reports, and do not rely on its deep scan for nested scripts or final approval.

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

T08 · Insecure Dependencies

Error
Location
scripts/check.py:93
Finding

Unpinned npx Package Execution Creates a Supply-Chain Code Execution Risk

Content
View full analysis

Vulnerability Details

File Location: scripts/check.py, line 93
Vulnerability Type: Unpinned executable dependency
Risk Level: High

python
# Use list form to avoid shell injection
stdout, stderr, code = run_command(["npx", "clawhub", "inspect", slug, "--json"])

The same unpinned npx clawhub invocation pattern is also used for file inspection, searching, and listing. SKILL.md similarly instructs users to invoke npx clawhub without a pinned package version.

Technical Analysis

Invoking a package through npx without pinning and locally provisioning a reviewed version can cause npm to resolve and download executable package code at runtime. Avoiding shell=True protects against shell metacharacter injection in the slug, but it does not protect against a compromised, malicious, or unexpectedly changed npm package.

npm package installation and lifecycle behavior occurs with the privileges of the user running the guardian. The subprocess also inherits the parent process environment because no restricted env is supplied to subprocess.run. Consequently, remotely resolved package code may be able to read workspace files, user configuration, npm credentials, API tokens, SSH material, and other environment variables accessible to that user.

This exceeds the minimum privileges needed for a read-only scanner: the implementation needs a known ClawHub client, but it delegates execution to a potentially mutable package resolved at runtime.

Attack Path

  1. An attacker compromises the npm package, its publisher account, or another relevant dependency in its dependency graph.
  2. The attacker publishes a malicious version that preserves expected CLI output while adding malicious installation or runtime behavior.
  3. A user runs scripts/check.py on an otherwise legitimate skill.
  4. npx resolves or downloads the unpinned package and executes attacker-controlled code.
  5. The malicious package runs ...[truncated 702 chars]
Remediation
View remediation

Remediation Suggestions

  • Install a reviewed ClawHub CLI version ahead of time and invoke its fixed executable directly rather than allowing npx to download packages on demand.
  • Pin an exact package version and verify its integrity using a committed lockfile and npm integrity metadata.
  • Use npx --no-install or the corresponding modern npm option so the scan fails if the approved local dependency is unavailable.
  • Consider vendoring or packaging the reviewed client as part of a reproducible deployment.
  • Run the external CLI with a minimal environment rather than inheriting all environment variables.
  • Execute the scanner in a sandbox with read-only workspace access, no unnecessary credentials, and restricted outbound networking.
  • Apply the same hardening to every npx clawhub invocation documented in SKILL.md and implemented in scripts/check.py.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/check.py:105
Finding

ClawHub Security Flags Are Ignored and Treated as a Passing Result

Content
View full analysis

Vulnerability Details

File Location: scripts/check.py, lines 105-110
Vulnerability Type: Fail-open security validation
Risk Level: High

python
# Check for any security flags in the data
if 'security' in data:
    return {
        "status": "CHECKED",
        "message": "Security report found",
        "passed": True
    }

Technical Analysis

The code checks only whether the ClawHub response contains a security field. It never examines the field's contents, severity, verdict, vulnerability list, or malicious-code indicators. Any parseable response containing that key is classified as passing, including a report that explicitly marks a skill as malicious.

This directly conflicts with the documented workflow in SKILL.md, which says that a flagged security report must cause an immediate abort. The report generator later relies on v1['passed'], so this unconditional True propagates into the overall recommendation.

The NO_REPORT branch is also fail-open and returns passed: True, meaning the absence of security evidence is represented as a successful check rather than an unknown or review-required state.

Attack Path

  1. An attacker publishes a skill that has been flagged by ClawHub or otherwise receives an adverse security report.
  2. The user runs the guardian against the attacker's slug.
  3. ClawHub returns valid JSON containing a security field with a failing or malicious verdict.
  4. The guardian checks only for the field's existence and sets passed to True.
  5. If the incomplete local pattern scanner finds no critical regex match, the final report states that the skill can proceed.
  6. The owner may install the malicious skill based on the guardian's incorrect assurance.
  7. Any malicious behavior in that installed skill then executes under the privileges granted to the skill runtime.

Impact Assessment

This flaw does not itself install or execute the inspecte ...[truncated 362 chars]

Remediation
View remediation

Remediation Suggestions

  • Parse the documented ClawHub security-report schema and explicitly validate its verdict, severity, and findings.
  • Maintain a strict allowlist of passing statuses; treat unknown, missing, malformed, or newly introduced statuses as non-passing.
  • Fail closed when the report is unavailable or cannot be interpreted.
  • Include the actual upstream verdict and findings in the owner-facing report.
  • Add tests for clean, malicious, flagged, missing-report, malformed-response, and unknown-status cases.
  • Ensure the code enforces the documented “flagged means abort” policy rather than relying on owner interpretation.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/check.py:233
Finding

Nested Script Paths Are Reduced to Basenames, Allowing Deep-Scan Bypass

Content
View full analysis

Vulnerability Details

File Location: scripts/check.py, lines 233-237
Vulnerability Type: Incomplete security scanning caused by incorrect path handling
Risk Level: High

python
# For script files (.py, .js, .sh), analyze content
if file.endswith(('.py', '.js', '.sh')):
    # Get the file name without path
    filename = file.split('/')[-1]
    content = fetch_file_content(slug, filename)

The relevant fetch helper forwards the supplied path to ClawHub:

python
def fetch_file_content(slug, file_path):
    """Fetch a single file's content from the skill."""
    # Use npx to get file content
    stdout, stderr, code = run_command(["npx", "clawhub", "inspect", slug, "--file", file_path])
    if code == 0 and stdout:
        return stdout
    return None

Technical Analysis

The file listing preserves relative paths, such as scripts/check.py, but the analyzer strips each script path to its basename before fetching it. It therefore requests check.py rather than scripts/check.py.

If ClawHub requires the listed relative path, the fetch fails and returns None. The caller silently skips analysis and records no error. The file is still counted in files_scanned, so the final message can misleadingly claim that it was deeply analyzed. The project itself uses the conventional nested scripts/check.py layout, making this flaw directly relevant to the files the scanner claims to inspect.

Basename conversion can also create ambiguity when multiple directories contain scripts with the same name. The scanner may fetch the wrong file or fail to fetch either one, while reporting no critical finding.

Attack Path

  1. An attacker publishes a skill containing malicious code at a nested path such as scripts/runner.py.
  2. The --files listing returns scripts/runner.py.
  3. The guardian reduces this path to runner.py.
  4. The content request for runner.py fails or resolves ...[truncated 925 chars]
Remediation
View remediation

Remediation Suggestions

  • Pass the exact relative path returned by the trusted file listing to fetch_file_content without reducing it to a basename.
  • Normalize paths using POSIX path rules and reject absolute paths, traversal components such as .., control characters, and malformed entries.
  • Treat every failed content fetch as a scan failure, not as a silently skipped file.
  • Track separate counters for discovered, fetched, successfully scanned, skipped, and failed files.
  • Require all executable or instruction-bearing files to be fetched successfully before phase two can pass.
  • Detect duplicate or ambiguous normalized paths.
  • Add tests covering nested scripts, duplicate basenames, paths with spaces, failed fetches, and malicious code under scripts/.
  • Prefer structured JSON file-list output from the CLI instead of parsing human-readable whitespace-delimited output.
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • 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 (11)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · scripts/check.py (reported line 65)May include surrounding context.

python
"""Run a command and return output."""
    try:
        if use_shell:
            result = subprocess.run(
                cmd, shell=True, capture_output=True, text=True, timeout=30
            )
        else:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill documents and requires capabilities equivalent to shell execution, network access, and filesystem reads, but it does not declare any explicit tool scope such as permissions or allowed-tools. For a security-sensitive installation guard, this creates a transparency and least-privilege problem: an agent may run broad commands without a machine-readable restriction boundary, increasing the chance of unintended or overbroad execution.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding

Using npx clawhub without a pinned version allows execution of whatever package version resolves at runtime, which can change over time or be compromised upstream. In this skill, that risk is amplified because the command is part of a security-verification workflow, so a malicious or breaking update could subvert the very checks meant to protect installation.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding

This unpinned npx clawhub invocation has the same supply-chain risk: it may fetch and execute a different package version than expected. Because this phase fetches files for code analysis, a compromised package could falsify results, hide malicious content, or run unintended code during inspection.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
90% confidence
Finding

The install command uses npx clawhub without version pinning, introducing supply-chain risk at the moment of installation. An attacker controlling or compromising the resolved package version could execute arbitrary logic or alter what gets installed, directly affecting the local environment.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
90% confidence
Finding

This workflow step again relies on an unpinned npx clawhub reference, so the behavior of a critical installation action is not stable or auditable. In the context of a 'security guardian' skill, this inconsistency undermines trust and could let a malicious upstream update bypass or weaken protections.

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 · scripts/check.py (reported line 65)May include surrounding context.

python
"""Run a command and return output."""
    try:
        if use_shell:
            result = subprocess.run(
                cmd, shell=True, capture_output=True, text=True, timeout=30
            )
        else:

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 · scripts/check.py (reported line 72)May include surrounding context.

python
# Use list form to avoid shell injection
            if isinstance(cmd, str):
                cmd = cmd.split()
            result = subprocess.run(
                cmd, capture_output=True, text=True, timeout=30
            )
        return result.stdout, result.stderr, result.returncode

Rp1

Medium
Category
MCP Rug Pull
Confidence
86% confidence
Finding

The script repeatedly executes 'npx clawhub ...' without pinning a specific package version or otherwise establishing trust for the resolved package. That creates a supply-chain risk: a malicious or compromised package version could be fetched and executed at runtime, undermining the very security check this skill is supposed to provide.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The advertised 'DEEP content analysis' is incomplete: nested script files are enumerated, but content fetches use only the basename, which can miss files in subdirectories or analyze the wrong file if names collide. This creates a false sense of safety and allows malicious code to evade scanning by being placed in nested paths, which is especially dangerous in a security-review skill.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill claims to require owner confirmation before installation, but the implementation only prints a warning and returns a proceed/fail status. In automated or chained workflows, downstream tooling may treat a successful exit as authorization to continue, creating a security control bypass through misleading UX and unmet policy guarantees.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/check.py:17