T09 · Insecure Skill Coding Practices
- 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: Highpython # 🔒 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
clawhubas an allowed command. Thestr.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-maliciousThis directly contradicts the claims in
SKILL.mdthat only whitelisted commands are executed and arbitrary or destructive command execution is prevented.Attack Path
- An attacker obtains control of, or influence over, the
commandargument passed toexec_command(). - The attacker constructs a string beginning with
clawhuband appends a shell operator and payload, such asclawhub; id. - The
startswith("clawhub")validation accepts the entire input. subprocess.getoutput()passes the attacker-controlled string to a system shell.- The shell interprets the appended operator and executes the arbitrary payload with the privileges of the skill process.
- 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]
- An attacker obtains control of, or influence over, the
- Remediation
View remediation
Remediation Suggestions
Replace shell-string execution with structured, shell-free process invocation:
- Accept a structured subcommand and argument list rather than one command string.
- Validate the executable as exactly
clawhub. - Maintain explicit allowlists for permitted
clawhubsubcommands and, where practical, their accepted options and argument formats. - Invoke the process with
subprocess.run()andshell=False. - Add an execution timeout, output-size controls, and consistent error handling.
- Avoid returning raw exception details if they may reveal sensitive system information.
- 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.
