T09 · Insecure Skill Coding Practices
- Location
scripts/update_openclaw_config.py:12- Finding
Shell Command Injection Through Unvalidated Service Mapping Data
- Content
View full analysis
str: """Run a shell command and return output.""" try: result = subprocess.run(cmd, shell=True, capture_output=True, text=True, check=True) return result.stdout.strip() except subprocess.CalledProcessError as e: print(f"Command failed: {cmd}") print(f"Error: {e.stderr}") return "" ``` ```python def get_openclaw_plugin_config(plugin_name: str) -> Dict: """Get current OpenClaw config for a plugin.""" cmd = f"openclaw config get plugins.entries.{plugin_name}" output = run_command(cmd) ``` ```python def update_plugin_config(plugin_name: str, base_url: str) -> bool: """Update OpenClaw config for a plugin.""" config_path = f"plugins.entries.{plugin_name}.config.baseUrl" cmd = f"openclaw config set {config_path} {base_url}" print(f"Updating {plugin_name}: {base_url}") output = run_command(cmd) ``` ```python for mapping in mappings: app_name = mapping['app_name'] proxy_port = mapping['proxy_port'] plugin_name = map_app_to_plugin(app_name) base_url = f"http://localhost:{proxy_port}" # Check current config current_config = get_openclaw_plugin_config(plugin_name) current_url = current_config.get('baseUrl', '') if current_url == base_url: print(f"{plugin_name}: Already configured correctly ✓") continue # Update config if update_plugin_config(plugin_name, base_url): updates_applied += 1 else: updates_failed += 1 ``` ### Technical Analysis The script loads `app_name` and `proxy_port` from a JSON mapping file. The file can be selected through the `--mappings-file` command-line option, and neither field is val ...[truncated 2382 chars]- Remediation
View remediation
str: try: result = subprocess.run( args, capture_output=True, text=True, check=True, ) return result.stdout.strip() except subprocess.CalledProcessError as exc: print(f"Command failed: {args!r}") print(f"Error: {exc.stderr}") return "" ``` Call it as follows: ```python run_command([ "openclaw", "config", "get", f"plugins.entries.{plugin_name}", ]) ``` ```python run_command([ "openclaw", "config", "set", config_path, base_url, ]) ``` 2. **Validate plugin names** Prefer an explicit allowlist of supported OpenClaw plugins. If arbitrary plugin names are required, enforce a restrictive pattern such as: ```python import re if not re.fullmatch(r"[A-Za-z0-9._-]+", plugin_name): raise ValueError("Invalid plugin name") ``` 3. **Validate ports as integers** Reject strings, booleans, shell syntax, and out-of-range values: ```python if isinstance(proxy_port, bool): raise ValueError("Invalid proxy port") proxy_port = int(proxy_port) if not 1 <= proxy_port <= 65535: raise ValueError("Proxy port is outside the valid range") ``` 4. **Validate the mapping schema** Before processing, ensure each entry is an object containing only expected fields with defined types. Reject malformed or unexpected values rather than attempting to use them. 5. **Treat externally supplied mapping files as untrusted** Document the trust boundary for `--mappings-file`. Avoid processing mapping files from shared or attacker-writable directories, and verify ownership and permissions when appropriat ...[truncated 281 chars]
