T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/upload_media.py:24
- Finding
- Bearer Token and Uploaded File Exposed Through Forced Plaintext HTTP## Vulnerability Details **File Location**: `scripts/upload_media.py`, lines 24-53 **Vulnerability Type**: Plaintext transmission of credentials and user-selected file contents **Risk Level**: High **Vulnerable Code**: ```python bridge = config["plugins"]["entries"]["astron-claw"]["config"]["bridge"] host = urlparse(bridge["url"]).netloc token = bridge["token"] return {"host": host, "token": token} ``` ```python url = f"http://{config['host']}/api/media/upload" filename = os.path.basename(file_path) with open(file_path, "rb") as f: resp = requests.post( url, headers={"Authorization": f"Bearer {config['token']}"}, files={"file": (filename, f)}, data={"sessionId": session_id} if session_id else {}, ) ``` ### Technical Analysis The script parses the configured bridge URL but preserves only its network location. It then reconstructs the upload endpoint with a hardcoded `http://` scheme. This discards any configured HTTPS scheme and forces the bearer token, uploaded file, filename, and optional session identifier to travel over an unencrypted connection. Because bearer tokens grant access to whoever possesses them, an attacker who can observe the network traffic can reuse the captured token without needing additional authentication. An active network attacker can also modify requests or responses, including substituting the returned public download URL. Reading a bridge credential and transmitting a caller-selected file are relevant to the declared authenticated-upload function. However, transmitting them over plaintext HTTP is not necessary and fails least-security expectations. ### Attack Path 1. A user invokes the Skill with a local file to upload. 2. The script reads the Astron Claw Bridge bearer token from `/root/.openclaw/openclaw.json`. 3. Even if the configured bridge URL uses HTTPS, the script removes that scheme and constructs an HTTP endpoint. 4. T ...[truncated 1203 chars]
- Remediation
- ## Remediation Suggestions - Preserve and validate the configured URL rather than extracting only its network location. - Require HTTPS for every authenticated upload and reject plaintext HTTP configuration. - Reject malformed URLs, credentials embedded in URLs, fragments, and unexpected schemes. - Construct the API endpoint from a validated HTTPS base URL. - Configure a finite connection and response timeout. - Keep TLS certificate verification enabled and do not introduce `verify=False`. - Consider restricting the bridge destination to an explicit allowlist if only known service origins are legitimate. - Avoid printing unrestricted server response bodies on errors because they may contain sensitive diagnostics. - Warn users that uploaded files will become publicly accessible and obtain clear confirmation before uploading sensitive files. Example hardened construction: ```python bridge_url = bridge["url"].rstrip("/") parsed = urlparse(bridge_url) if parsed.scheme != "https" or not parsed.netloc: raise ValueError("Bridge URL must be a valid HTTPS URL") if parsed.username or parsed.password or parsed.fragment: raise ValueError("Bridge URL contains prohibited components") url = f"{bridge_url}/api/media/upload" resp = requests.post( url, headers={"Authorization": f"Bearer {config['token']}"}, files={"file": (filename, f)}, data={"sessionId": session_id} if session_id else {}, timeout=(10, 120), ) ```
