Back to skill

Security audit

Exec Tool

Security checks for vulnerabilities and agentic risk

Overview

This skill is meant to run ClawHub CLI commands, but its safety boundary is ineffective and could allow arbitrary shell commands despite claims that destructive commands are prevented.

Review before installing. This should only be used in a tightly sandboxed environment, with a minimally privileged account, and only after replacing the raw shell string execution with structured `clawhub` subcommand validation using `shell=False`. Do not expose this function to chat, webhooks, agents, or untrusted input in its current form.

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

T09 · Insecure Skill Coding Practices

Error
Location
tool.py:8
Finding

Shell Command Injection Through Inadequate Command Allowlisting

Content
View full analysis

Vulnerability Details

File Location: tool.py, lines 8–14
Vulnerability Type: Shell command injection caused by unsafe prefix validation and shell-based execution
Risk Level: High

python
    # 🔒 Basic safety restriction (VERY IMPORTANT)
    allowed_commands = ["clawhub"]

    if not any(command.startswith(cmd) for cmd in allowed_commands):
        return "Command not allowed"

    try:
        result = subprocess.getoutput(command)

Technical Analysis

The function treats any string beginning with clawhub as an allowed command. The str.startswith() check does not verify an exact executable token, validate subcommands or arguments, or prevent shell metacharacters.

The accepted string is passed to subprocess.getoutput(), which executes it through the system shell. Consequently, shell separators, command substitution, pipelines, and redirections remain active. Inputs such as the following pass the prefix check:

text
clawhub; id
clawhub && cat /etc/passwd
clawhub$(arbitrary_command)
clawhub-malicious

This directly contradicts the claims in SKILL.md that only whitelisted commands are executed and arbitrary or destructive command execution is prevented.

Attack Path

  1. An attacker obtains control of, or influence over, the command argument passed to exec_command().
  2. The attacker constructs a string beginning with clawhub and appends a shell operator and payload, such as clawhub; id.
  3. The startswith("clawhub") validation accepts the entire input.
  4. subprocess.getoutput() passes the attacker-controlled string to a system shell.
  5. The shell interprets the appended operator and executes the arbitrary payload with the privileges of the skill process.
  6. The first 4,000 characters of command output are returned to the caller, which may also facilitate extraction of local information.

Impact Assessment

Successful exploitation permits arbitrary operating-system command execution under the acco ...[truncated 667 chars]

Remediation
View remediation

Remediation Suggestions

Replace shell-string execution with structured, shell-free process invocation:

  1. Accept a structured subcommand and argument list rather than one command string.
  2. Validate the executable as exactly clawhub.
  3. Maintain explicit allowlists for permitted clawhub subcommands and, where practical, their accepted options and argument formats.
  4. Invoke the process with subprocess.run() and shell=False.
  5. Add an execution timeout, output-size controls, and consistent error handling.
  6. Avoid returning raw exception details if they may reveal sensitive system information.
  7. Run the skill under a dedicated, minimally privileged account with restricted filesystem and network access.

Example hardened pattern:

python
import subprocess

ALLOWED_SUBCOMMANDS = {"search", "install"}

def exec_command(subcommand: str, args: list[str]) -> str:
    if subcommand not in ALLOWED_SUBCOMMANDS:
        return "Command not allowed"

    try:
        result = subprocess.run(
            ["clawhub", subcommand, *args],
            shell=False,
            capture_output=True,
            text=True,
            timeout=30,
            check=False,
        )
        output = result.stdout if result.returncode == 0 else result.stderr
        return output[:4000]
    except subprocess.TimeoutExpired:
        return "Command timed out"

Argument validation should also be tailored to each permitted subcommand; disabling the shell prevents metacharacters from being interpreted but does not by itself prevent misuse of dangerous native CLI options.

Vulnerability Patterns
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The docstring and safety comment claim the command execution is safe, but the implementation is not actually safe because it executes the provided shell string after only a superficial prefix check. This mismatch is dangerous because it can mislead reviewers and downstream users into trusting code that is vulnerable to shell injection.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
98% confidence
Finding

The function passes a user-controlled string directly to subprocess.getoutput, which executes it via the shell. The only protection is a prefix check for clawhub, but that can be bypassed with shell metacharacters such as clawhub; <other command> or clawhub && <other command>, enabling arbitrary command execution.

Content

Scanner excerpt · tool.py (reported line 15)May include surrounding context.

python
return "Command not allowed"

    try:
        result = subprocess.getoutput(command)
        return result[:4000]  # Telegram limit safe
    except Exception as e:
        return str(e)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The function executes a shell command via subprocess.getoutput, which is a safety-relevant operation, but there is no visible confirmation prompt or user-facing warning before execution. The docstring describes the command as 'safe' rather than disclosing that arbitrary shell execution is being performed within the allowed prefix.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.