T09 · Insecure Skill Coding Practices
- Location
scripts/miro_api.py:88- Finding
OAuth credentials and tokens are transmitted in URL query parameters
- Content
View full analysis
Dict[str, Any]: url = TOKEN_URL + "?" + urllib.parse.urlencode(params) req = urllib.request.Request(url, method="POST") try: with urllib.request.urlopen(req) as resp: return json.loads(resp.read().decode("utf-8", errors="replace")) except urllib.error.HTTPError as e: body = e.read().decode("utf-8", errors="replace") try: parsed = json.loads(body) if body else {"error": str(e)} except json.JSONDecodeError: parsed = {"error": body or str(e)} print_json(parsed) sys.exit(1) def exchange_code(client_id: str, client_secret: str, redirect_uri: str, code: str) -> Dict[str, Any]: return token_request({ "grant_type": "authorization_code", "client_id": client_id, "client_secret": client_secret, "code": code, "redirect_uri": redirect_uri, }) def refresh_token(client_id: str, client_secret: str, refresh_token_value: str) -> Dict[str, Any]: return token_request({ "grant_type": "refresh_token", "client_id": client_id, "client_secret": client_secret, "refresh_token": refresh_token_value, }) ``` ### Technical Analysis The token endpoint request uses the POST method but places all OAuth parameters in the URL query string rather than in the request body. Consequently, the following sensitive values may appear in the complete URL: - Miro OAuth client secret - Authorization code - Refresh token - Client identifier and redirect URI The destination is the official HTTPS Miro token endpoint, so sending these credentials to that service is necessary for the declared OAuth functionality. TLS also protects the request while it i ...[truncated 1718 chars]- Remediation
View remediation
Dict[str, Any]: data = urllib.parse.urlencode(params).encode("utf-8") req = urllib.request.Request( TOKEN_URL, data=data, headers={ "Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json", }, method="POST", ) with urllib.request.urlopen(req) as resp: return json.loads(resp.read().decode("utf-8", errors="replace")) ``` 2. Ensure request URLs, headers, and bodies containing credentials are not emitted to logs. 3. Configure HTTP diagnostics and exception telemetry to redact `client_secret`, `code`, `access_token`, and `refresh_token`. 4. Rotate any client secret or refresh token that may already have been captured in URL logs. 5. Add automated tests asserting that the token endpoint URL has no sensitive query parameters. ]]>
