T09 · Insecure Skill Coding Practices
- Location
scripts/wc_client.py:93- Finding
API Key Disclosure Through an Unrestricted API Base URL Override
- Content
View full analysis
Vulnerability Details
File Location:
scripts/wc_client.py:93-103andscripts/wc_client.py:213-245
Vulnerability Type: Arbitrary-origin transmission of authentication credentials
Risk Level: HighVulnerable Code
python def _api_key() -> str: key = os.environ.get("SOCCER_API_KEY") return key or request_agent_temp_key()["api_key"] def _permanent_api_key_configured() -> bool: return bool(os.environ.get("SOCCER_API_KEY")) def _base_url() -> str: return os.environ.get("WORLDCUP_API_BASE", DEFAULT_BASE_URL).rstrip("/")python def _request( method: str, path: str, payload: Optional[dict] = None, *, require_auth: bool = True, api_key: Optional[str] = None, ) -> Any: """Issue an HTTP request and map errors to WorldCupAPIError. Shared by GET (list_teams) and POST (predict_match). The application response envelope is identical across both endpoints. """ url = f"{_base_url()}{path}" headers = {"Accept": "application/json"} if require_auth: headers["X-API-Key"] = api_key or _api_key() if method == "POST": headers["Content-Type"] = "application/json" try: if _BACKEND == "httpx": if method == "POST": resp = httpx.post(url, json=payload, headers=headers, timeout=DEFAULT_TIMEOUT) else: resp = httpx.get(url, params=payload, headers=headers, timeout=DEFAULT_TIMEOUT) else: # requests fallback if method == "POST": resp = requests.post(url, json=payload, headers=headers, timeout=DEFAULT_TIMEOUT) else: resp = requests.get(url, params=payload, headers=headers, timeout=DEFAULT_TIMEOUT)Technical Analysis
The client reads
WORLDCUP_API_BASEdirectly from the environment and uses it to construct every API URL without validating the destination scheme, hostname, port, or trust level. For authenticated endpoints, ...[truncated 2061 chars]- Remediation
View remediation
Remediation Suggestions
- Parse the base URL with
urllib.parse.urlparseand reject malformed URLs, embedded credentials, fragments, and unexpected schemes. - Require HTTPS for all non-loopback destinations.
- Allowlist
www.jiajielitong.comfor normal production operation. - Place staging and local endpoint overrides behind an explicit development-mode setting that is disabled by default.
- Do not attach
SOCCER_API_KEYwhen the configured origin differs from the approved production origin. - Use a separate, explicitly configured development credential for staging endpoints.
- If localhost support is required, restrict it to loopback addresses and refuse to forward production credentials.
- Consider refusing redirects or validating every redirect destination before retaining the authentication header.
- Add tests confirming that credentials are not sent to HTTP endpoints, arbitrary hosts, redirect targets, or custom ports.
- Document the trust boundary and warn operators that endpoint overrides must never receive production credentials.
- Parse the base URL with
