T09 · Insecure Skill Coding Practices
- Location
- templates/buddy_oauth_callback_local.py:42
- Finding
- OAuth credentials may be transmitted to an arbitrary or plaintext token endpoint<![CDATA[ ## Vulnerability Details **File Locations**: - `templates/buddy_oauth_callback_local.py:42,86-105` - `templates/buddy_oauth_callback_scf.py:34,70-90` **Vulnerability Type**: Unvalidated sensitive-data destination and insecure transport **Risk Level**: High ### Vulnerable Code Local callback implementation: ```python TOKEN_ENDPOINT = os.environ.get("WB_TOKEN_ENDPOINT", "") def exchange_code(code: str) -> dict: """Authorization-code exchange.""" if not TOKEN_ENDPOINT: raise RuntimeError( "WB_TOKEN_ENDPOINT is not configured" ) form = { "grant_type": "authorization_code", "code": code, "redirect_uri": REDIRECT_URI, "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET, } req = urllib.request.Request( TOKEN_ENDPOINT, data=urllib.parse.urlencode(form).encode("utf-8"), headers={ "Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json", }, method="POST", ) with urllib.request.urlopen(req, timeout=15) as resp: return json.loads(resp.read().decode("utf-8")) ``` Serverless callback implementation: ```python TOKEN_ENDPOINT = os.environ.get("WB_TOKEN_ENDPOINT", "") def exchange_code(code: str) -> dict: """Exchange an authorization code for a token.""" if not TOKEN_ENDPOINT: raise RuntimeError( "WB_TOKEN_ENDPOINT is not configured" ) form = { "grant_type": "authorization_code", "code": code, "redirect_uri": REDIRECT_URI, "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET, } req = urllib.request.Request( TOKEN_ENDPOINT, data=urllib.parse.urlencode(form).encode("utf-8"), headers={ "Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json", }, method="POST", ) with urllib.request. ...[truncated 2336 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse the endpoint before processing any callback: ```python from urllib.parse import urlsplit ALLOWED_TOKEN_HOSTS = { "approved-token-host.example", } def validate_token_endpoint(value: str) -> str: parsed = urlsplit(value) if parsed.scheme != "https": raise RuntimeError("The OAuth token endpoint must use HTTPS") if parsed.hostname not in ALLOWED_TOKEN_HOSTS: raise RuntimeError("The OAuth token endpoint host is not approved") if parsed.username or parsed.password: raise RuntimeError("Embedded URL credentials are prohibited") if parsed.fragment: raise RuntimeError("Token endpoint fragments are prohibited") if parsed.port not in (None, 443): raise RuntimeError("Unexpected token endpoint port") return value ``` 2. Prefer a fixed endpoint supplied by trusted application configuration rather than a freely configurable URL. 3. Validate the endpoint during application startup so an unsafe deployment fails before accepting callbacks. 4. Use TLS certificate validation and do not disable Python's default certificate checks. 5. Prevent or tightly control redirects during token exchange. If redirects are required, revalidate every destination before transmitting sensitive data. 6. Never include authorization codes, secrets, or full tokens in logs or error responses. 7. Add tests that reject HTTP, loopback, link-local, private-network, credential-bearing, and unapproved-host URLs. ]]>
