T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/zoodata.py:338
- Finding
- Bearer Credential Can Be Forwarded to an Untrusted Redirect Destination<![CDATA[ ## Vulnerability Details **File Location**: `scripts/zoodata.py:338-378` **Vulnerability Type**: Improper authorization-header handling across HTTP redirects **Risk Level**: Medium ### Vulnerable Code ```python def api_call(endpoint: str, params: dict) -> dict: """ Make a POST request to ZooData API with retry and error handling. Returns the parsed JSON response on success, with _query metadata injected. Exits with a clear error message on failure. """ global _last_request_time url = f"{BASE_URL}/{endpoint}" if not BASE_URL_TRUSTED: print(f"ERROR: refusing to send your API key to untrusted host '{_host_of(BASE_URL)}'. " "Set ZOODATA_BASE_URL to a zoodata.ai host or localhost, or unset it.", file=sys.stderr) sys.exit(1) api_key = get_api_key() # Clean params: remove None values params = {k: v for k, v in params.items() if v is not None} # Quirk: topN and newProductPeriod must be strings for str_field in ("topN", "newProductPeriod"): if str_field in params and not isinstance(params[str_field], str): params[str_field] = str(params[str_field]) # Save the actual params sent to API (for _query metadata) actual_params = dict(params) body = json.dumps(params).encode("utf-8") headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", "User-Agent": "ZooData-CLI/1.0 (Python)", } # Rate-limit pacing: enforce minimum interval between requests now = time.monotonic() elapsed = now - _last_request_time if elapsed < MIN_REQUEST_INTERVAL: time.sleep(MIN_REQUEST_INTERVAL - elapsed) delay = RETRY_DELAY max_attempts = MAX_RETRIES for attempt in range(1, max(MAX_RETRIES, RATE_LIMIT_RETRIES) + 1): _last_request_time = time.monotonic() try: req = urllib.request.Request(url, data=body, headers=headers, method="POST") ...[truncated 2060 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Disable automatic redirects for authenticated API requests unless redirects are explicitly required. 2. Implement a custom `HTTPRedirectHandler` that: - Parses and validates every redirect target. - Rejects redirects to non-HTTPS destinations. - Rejects cross-origin redirects or removes `Authorization` before following them. - Applies the same normalized-origin allowlist to every redirect hop. 3. Compare the complete origin—scheme, normalized hostname, and effective port—rather than only the hostname. 4. Prefer rejecting redirects from API endpoints entirely, because a stable API base URL should not normally require them. 5. Add automated tests covering: - Same-origin HTTPS redirects. - Cross-origin redirects. - Redirects from HTTPS to HTTP. - Redirects to loopback and non-ZooData hosts. - Verification that no bearer header reaches a rejected destination. ]]>
