T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/catch_pet.py:25
- Finding
- Bearer Credential Can Be Transmitted Without Enforced HTTPS## Vulnerability Details **File Location**: `scripts/catch_pet.py`, lines 25–26 and 36–48 **Vulnerability Type**: Sensitive credential transmission without transport-security validation **Risk Level**: Medium ### Vulnerable Code ```python config = { "CATCH_API_URL": os.environ.get("CATCH_API_URL") or meta.get("CATCH_API_URL") or "", "API_KEY": os.environ.get("API_KEY") or meta.get("API_KEY") or "", } ``` ```python def build_request(url: str, api_key: str) -> urllib.request.Request: payload = json.dumps({"action": "catch"}).encode("utf-8") return urllib.request.Request( url, data=payload, headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", "Accept": "application/json", }, method="POST", ) ``` ### Technical Analysis The Skill must send an API credential to the user-configured pet backend, so authenticated network access is necessary for its declared functionality. However, `CATCH_API_URL` is accepted without validating its URL scheme, host, or redirect behavior. Consequently, an `http://` URL can receive the bearer credential over an unencrypted connection. The use of `urllib.request.urlopen()` also permits standard redirect handling without an explicit policy that requires redirects to remain on HTTPS and within the intended trust boundary. This does not constitute covert exfiltration: the documentation discloses the API request and bearer authentication. The vulnerability is that transport and destination safeguards are not enforced before sensitive information is transmitted. ### Attack Path 1. A malicious or mistaken configuration sets `CATCH_API_URL` to a plaintext HTTP endpoint. Alternatively, a configured endpoint responds with a redirect toward an unintended destination. 2. `load_config()` accepts the URL without scheme or destination validation. 3. `build_request()` places `API_KEY` in the `Authorization: Bearer` header ...[truncated 845 chars]
- Remediation
- ## Remediation Suggestions 1. Parse `CATCH_API_URL` with `urllib.parse.urlsplit()` and require the `https` scheme before constructing the request. 2. Reject URLs with missing hosts, embedded user information, fragments, malformed ports, or unsupported schemes. 3. Disable automatic redirects or implement a custom redirect handler that permits a redirect only when: - the destination still uses HTTPS; - the destination host is explicitly trusted; - no downgrade to HTTP occurs; and - credentials are not forwarded across trust boundaries. 4. Prefer an explicit allowlist of backend hosts when the deployment model permits it. 5. Use a narrowly scoped, revocable API key that authorizes only required catch operations. 6. Keep production credentials in a protected secret store or environment variable rather than `_meta.json`. 7. Document the HTTPS-only requirement in `SKILL.md` and `references/api.md`. 8. Add tests confirming rejection of HTTP URLs, malformed URLs, HTTPS-to-HTTP redirects, and cross-host redirects. Example validation: ```python from urllib.parse import urlsplit def validate_api_url(url: str) -> str: parsed = urlsplit(url) if parsed.scheme.lower() != "https": raise ConfigError("CATCH_API_URL must use HTTPS.") if not parsed.hostname or parsed.username or parsed.password: raise ConfigError("CATCH_API_URL is invalid or contains embedded credentials.") if parsed.fragment: raise ConfigError("CATCH_API_URL must not contain a fragment.") return url ``` Apply this validation before passing the URL to `build_request()`, together with a restrictive redirect policy.
