T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/runninghub_app.py:100
- Finding
- RunningHub API Key Exposure Through Chat, Command-Line Arguments, URL Query Strings, and Plaintext Configuration<![CDATA[ ## Vulnerability Details **File Location**: - `references/api-key-setup.md:12-27` - `scripts/runninghub_app.py:61-70` - `scripts/runninghub_app.py:100-102` - `scripts/runninghub_app.py:156-167` - `scripts/runninghub.py:156-165` - `scripts/runninghub.py:242-247` - `scripts/runninghub.py:361-365` **Vulnerability Type**: Sensitive credential exposure caused by insecure secret collection, storage, and transmission practices **Risk Level**: High ### Vulnerable Code The setup instructions encourage users to provide an API key through an ordinary chat channel and interpolate it directly into a command that writes plaintext configuration: ```markdown - `"no_key"` → Guide: 1) Register at runninghub.cn 2) Create Key 3) Recharge 4) Send Key to me ## Save Key When user sends a key, verify with `--check --api-key THE_KEY`. If valid, save it: ```bash python3 -c " import json, pathlib p = pathlib.Path.home() / '.openclaw' / 'openclaw.json' p.parent.mkdir(exist_ok=True) cfg = json.loads(p.read_text()) if p.exists() else {} cfg.setdefault('skills', {}).setdefault('entries', {}).setdefault('runninghub', {})['apiKey'] = 'THE_KEY' p.write_text(json.dumps(cfg, indent=2)) " ``` ``` The AI Application client places the API key in curl process arguments as multipart form data: ```python def curl_upload(url: str, api_key: str, file_path: str, timeout: int = 120) -> subprocess.CompletedProcess: cmd = [ "curl", "-s", "-S", "--fail-with-body", "-X", "POST", url, "--max-time", str(timeout), "-H", f"Host: {API_HOST.split('//')[1]}", "-F", f"apiKey={api_key}", "-F", "fileType=input", "-F", f"file=@{file_path}", ] return subprocess.run(cmd, capture_output=True, text=True) ``` It also includes the key in a GET query string: ```python def get_node_info(api_key: str, webapp_id: str) -> list[dict]: url = f"{API_HOST}{NODE_INFO_PATH}?apiKey={api_key}&webappId={webapp_id}" result = curl_get(url) resp = _parse ...[truncated 5900 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Do not request API keys in ordinary chat** - Replace the instruction to “send the key” with a dedicated secret-entry or credential-management workflow. - Ensure secrets are excluded from conversation history, telemetry, and model context wherever the host platform supports secret inputs. - Instruct users who previously sent a key in chat to revoke and rotate it. 2. **Remove command-line secret arguments** - Deprecate `--api-key` for routine use because command arguments may be observable. - Resolve the key from a protected secret store or narrowly scoped environment variable. - Avoid constructing curl arguments containing bearer headers or secret multipart values. - Prefer an in-process HTTPS client where headers are never placed in a child process argument vector. If curl must be retained, pass sensitive configuration through protected standard input or a temporary config file with mode `0600`, then delete it promptly. 3. **Never put credentials in URLs** - Replace: ```python f"{API_HOST}{NODE_INFO_PATH}?apiKey={api_key}&webappId={webapp_id}" ``` with an authenticated request using an `Authorization: Bearer` header, provided the RunningHub API supports it. - If the upstream API requires an `apiKey` parameter, use a POST body rather than a GET query and request that the provider add header-based authentication. - Configure all relevant proxies and application logs to redact `apiKey`, `Authorization`, and similar sensitive fields. 4. **Harden local storage** - Use the platform's native encrypted secret store instead of storing the key in `openclaw.json`. - If file storage is unavoidable, create both the directory and file with restrictive permissions and validate them before reading: ```python p.parent.mkdir(mode=0o700, parents=True, exist_ok=True) fd = os.open(p, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600) ``` - Reject insecure ownership or ...[truncated 996 chars]
