Back to skill

Security audit

ModelCLI

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its local ModelCLI purpose, but it can automatically download and execute an unpinned remote installer during ordinary use.

Review this skill carefully before installing. Its media and model-management features are coherent, but on a machine without ModelCLI it may run a shell installer fetched live from GitHub, and normal invocations allow model downloads. Prefer installing ModelCLI yourself from a trusted, pinned source first, and use this skill only if you accept that network and persistent local-install behavior.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Findings (1)

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/invoke.py:16
Finding

Automatic Execution of an Unpinned Remote Installation Script

Content
View full analysis

Vulnerability Details

File Location: scripts/invoke.py:16, 100-135
Vulnerability Type: Remote payload retrieval and execution without integrity verification
Risk Level: Critical

Vulnerable Code

python
INSTALL_URL = "https://raw.githubusercontent.com/GraySilver/modelcli/main/install.sh"
python
if script is None:
    temporary = tempfile.TemporaryDirectory(prefix="modelcli-skill-install-")
    script = Path(temporary.name) / "install.sh"
    downloader = shutil.which("curl")
    if downloader:
        download = subprocess.run(
            [downloader, "-LsSf", INSTALL_URL, "-o", str(script)],
            capture_output=True,
            text=True,
            timeout=remaining_seconds(deadline),
            check=False,
        )
    else:
        wget = shutil.which("wget")
        if not wget:
            return None, "curl or wget is required to install ModelCLI"
        download = subprocess.run(
            [wget, "-qO", str(script), INSTALL_URL],
            capture_output=True,
            text=True,
            timeout=remaining_seconds(deadline),
            check=False,
        )
    if download.returncode != 0:
        return None, (download.stderr or download.stdout or "failed to download install.sh").strip()
result = subprocess.run(
    ["sh", str(script)],
    capture_output=True,
    text=True,
    timeout=remaining_seconds(deadline),
    check=False,
)

Technical Analysis

When the modelcli executable is unavailable, the wrapper automatically downloads install.sh from the mutable main branch of a personal GitHub repository and executes it with sh. The downloaded content is not pinned to an immutable commit or release, and the wrapper performs no checksum, signature, or provenance verification before execution.

HTTPS provides transport protection but does not guarantee that the repository's current content matches the code reviewed during this audit. The effective executable payload can change a ...[truncated 2104 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove automatic remote installation from normal inference and diagnostic execution paths. If modelcli is absent, return a clear error and require the user or administrator to install it separately.
  2. Require explicit user confirmation before performing any installation or executing installation code.
  3. Use a trusted, versioned release artifact rather than a mutable branch URL.
  4. Pin the installer or package to an immutable release or commit and verify a hard-coded cryptographic digest, such as SHA-256, before execution.
  5. Prefer cryptographic signature verification using a trusted public key so authenticity and integrity are independently established.
  6. Fail closed if verification fails, the signature is missing, the digest differs, or the retrieved artifact redirects to an unapproved origin.
  7. Prefer a reviewed operating-system package, signed package repository, or isolated package-management workflow over executing a downloaded shell script.
  8. Run installation with the least-privileged account possible and isolate it from credentials, sensitive files, and unnecessary network access.
  9. Record the verified version, source, and digest in diagnostic output to support reproducible auditing.
Vulnerability Patterns
  • 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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (11)

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The wrapper contains undisclosed auto-install behavior for a supposedly local tool and can download and execute a remote installer script. This violates least surprise and materially broadens capability from local inference/management to arbitrary remote bootstrap, creating a severe supply-chain and remote-code-execution risk. The discrepancy with the skill description makes the behavior more dangerous, not less.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

This block performs network-backed bootstrap by downloading an installer script from GitHub and then executing it. That enables unreviewed remote code to run in the user's environment and exceeds the skill's stated purpose of using a local ModelCLI. Because the network activity is embedded in normal execution when the binary is missing, users may trigger it unintentionally.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill invokes local scripts and shell-accessible functionality but does not declare an explicit tool scope such as permissions or allowed-tools. This weakens policy enforcement and reviewability: an agent may be allowed to execute environment or shell operations broader than users or platform policy expect, increasing the chance of unintended command execution or file access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill explicitly states that the wrapper will automatically install missing ModelCLI components and allow model downloads during normal execution, but the user-facing description does not warn about these side effects. This can lead to unanticipated network access, package installation, disk usage, and supply-chain exposure during seemingly routine OCR/ASR/TTS tasks.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill description and default prompt are written only in Chinese, which can impose a language constraint on users without offering a choice or explaining that the skill is intended for a Chinese-only context. This matches the policy category for language or locale constraints lacking user opt-in or clear justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The entire protocol documentation is written in Chinese, and there is no indication that users may choose another language or that the skill is intentionally limited to a Chinese-language context. The policy explicitly calls for flagging language or locale constraints that are imposed without user opt-in or clear justification.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
95% confidence
Finding

This subprocess fetches an install script from a remote URL using curl. While the download itself is not code execution, it is part of a bootstrap flow that immediately executes the retrieved script, making the fetch a critical part of a supply-chain attack surface. In a skill advertised for local model operations, hidden network bootstrap behavior is especially risky and unexpected.

Content

Scanner excerpt · scripts/invoke.py (reported line 104)May include surrounding context.

python
script = Path(temporary.name) / "install.sh"
            downloader = shutil.which("curl")
            if downloader:
                download = subprocess.run(
                    [downloader, "-LsSf", INSTALL_URL, "-o", str(script)],
                    capture_output=True,
                    text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
95% confidence
Finding

This wget path is an alternate remote installer download mechanism and carries the same supply-chain risk as the curl branch. Because the fetched script is later executed, an attacker controlling or tampering with the source can achieve arbitrary code execution. The skill context increases concern because users would reasonably expect local tooling, not downloader behavior.

Content

Scanner excerpt · scripts/invoke.py (reported line 115)May include surrounding context.

python
wget = shutil.which("wget")
                if not wget:
                    return None, "curl or wget is required to install ModelCLI"
                download = subprocess.run(
                    [wget, "-qO", str(script), INSTALL_URL],
                    capture_output=True,
                    text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
98% confidence
Finding

The code executes an installation script via sh after optionally downloading it from a remote GitHub URL. This creates a direct remote-code-execution supply-chain risk: if the URL, transport, repository, or script contents are compromised, arbitrary shell commands run with the user's privileges. The skill context makes this more dangerous because the manifest describes local ModelCLI use, not remote bootstrap and script execution.

Content

Scanner excerpt · scripts/invoke.py (reported line 124)May include surrounding context.

python
)
            if download.returncode != 0:
                return None, (download.stderr or download.stdout or "failed to download install.sh").strip()
        result = subprocess.run(
            ["sh", str(script)],
            capture_output=True,
            text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
92% confidence
Finding

The wrapper always invokes ModelCLI with --allow-download, permitting network retrievals during otherwise local operations. This expands the trust boundary and can cause unexpected fetching of models or artifacts, increasing supply-chain and data exposure risk beyond the stated local-only skill purpose. The danger is elevated by the mismatch between the advertised local scope and the actual network-enabled execution path.

Content

Scanner excerpt · scripts/invoke.py (reported line 213)May include surrounding context.

python
return emit_error("MODELCLI_INSTALL_FAILED", install_error or "ModelCLI installation failed", 4, retryable=True)

    try:
        completed = subprocess.run(
            [executable, "--json", "--allow-download", *command],
            capture_output=True,
            text=True,

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Always supplying --allow-download causes the wrapper to permit network downloads even for commands that should be satisfied locally. This increases attack surface, may fetch untrusted artifacts, and can undermine user expectations about offline/local processing. In the context of a skill marketed around local ModelCLI capabilities, this hidden network enablement is particularly problematic.

Content

No source excerpt is available for this finding.