T09 · Insecure Skill Coding Practices
- Location
scripts/server.py:168- Finding
Shell Command Whitelist Bypass Enables Arbitrary Command Execution
- Content
View full analysis
Vulnerability Details
File Location:
scripts/server.py:168-182
Vulnerability Type: OS command injection caused by unsafe shell execution
Risk Level: CriticalVulnerable Code
python def tool_run_command(command: str): """Execute a shell command (whitelist enforced).""" cmd_parts = command.strip().split() if not cmd_parts: return {"success": False, "error": "Empty command"} base = cmd_parts[0] if base not in CONFIG["allowed_commands"]: return { "success": False, "error": f"Command '{base}' not allowed. Allowed: {', '.join(CONFIG['allowed_commands'])}", } try: result = subprocess.run( command, shell=True, capture_output=True, text=True, timeout=30 )Technical Analysis
The whitelist validates only the first whitespace-delimited token. The entire attacker-controlled command is subsequently passed to
subprocess.run()withshell=True.Shell metacharacters such as semicolons, pipes, command substitution, redirection, and logical operators remain active. An input beginning with an allowed command can therefore append an arbitrary second command. For example, a request conceptually equivalent to
ls /tmp; <arbitrary command>passes thebase == "ls"check, after which the shell executes both portions.The configured command list also includes general-purpose interpreters such as
python3andnode. Even if metacharacters were filtered, access to these interpreters inherently permits execution of arbitrary code, filesystem access, and network operations under the server account.Attack Path
- The attacker obtains, guesses, or reuses the shared API key.
- The attacker sends an authenticated POST request to
/tools/run-command. - The supplied
commandbegins with an allowed executable such asls. - The attacker appends a shell operator followed by an ot ...[truncated 813 chars]
- Remediation
View remediation
Remediation Suggestions
- Remove
shell=Trueand execute commands as argument arrays, for example withsubprocess.run([executable, *validated_args], shell=False, ...). - Do not accept a free-form command string. Define separate operations with typed parameters for each supported action.
- Validate the executable path and every argument against an operation-specific policy.
- Remove
python3,node, and other general-purpose interpreters from the allowlist. - Reject shell metacharacters rather than attempting to escape them, although this must not replace
shell=False. - Execute tools under a dedicated, unprivileged operating-system account.
- Add filesystem, process, network, CPU, memory, and execution-time restrictions through a container or another sandbox.
- Record security audit events without logging secrets or sensitive command output.
- Remove
