T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/whoop_oauth_login.py:37
- Finding
- OAuth Authorization Flow Lacks State Validation and PKCE Binding<![CDATA[ ## Vulnerability Details **File Location**: `scripts/whoop_oauth_login.py:37-47, 57-76, 119-142`; `scripts/whoop_token.py:89-100` **Vulnerability Type**: OAuth login CSRF and authorization-response substitution **Risk Level**: High ### Vulnerable Code ```python def parse_code(user_input: str) -> str: s = user_input.strip() if s.startswith("http://") or s.startswith("https://"): u = urllib.parse.urlparse(s) q = urllib.parse.parse_qs(u.query) code = (q.get("code") or [None])[0] if code: return code raise SystemExit("Could not find ?code= in the pasted redirect URL") return s ``` ```python q = urllib.parse.parse_qs(parsed.query) code = (q.get("code") or [None])[0] if code: got["code"] = code ``` ```python params = { "client_id": client_id, "redirect_uri": redirect_uri, "response_type": "code", "scope": scopes, } auth_url = OAUTH_AUTH_URL + "?" + urllib.parse.urlencode(params) ``` ```python tok = exchange_code_for_token( code=code, client_id=client_id, client_secret=client_secret, redirect_uri=redirect_uri, ) ``` ```python def exchange_code_for_token(*, code: str, client_id: str, client_secret: str, redirect_uri: str) -> Dict[str, Any]: tok = _post_form( OAUTH_TOKEN_URL, { "grant_type": "authorization_code", "code": code, "client_id": client_id, "client_secret": client_secret, "redirect_uri": redirect_uri, }, ) _annotate_expiry(tok) return tok ``` ### Technical Analysis The authorization request does not include a cryptographically random OAuth `state` parameter. Neither the copy-and-paste callback parser nor the loopback HTTP handler validates that a callback belongs to the authorization request initiated by the current process. The implementation also does not use PKCE. It therefore has no `code_challenge` in the authorization request and no corresp ...[truncated 1767 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Generate a cryptographically random `state` value using `secrets.token_urlsafe()`. 2. Store the expected state only for the lifetime of the pending login. 3. Include `state` in the WHOOP authorization URL. 4. Require the callback to contain exactly the expected state and reject missing, mismatched, expired, or reused values. 5. Implement PKCE with a high-entropy `code_verifier` and an S256 `code_challenge`. 6. Include `code_challenge` and `code_challenge_method=S256` in the authorization request. 7. Include the original `code_verifier` in the token exchange. 8. Apply identical state and PKCE validation to both copy-and-paste and loopback modes. 9. Reject OAuth error callbacks explicitly and enforce a short expiration time for pending login state. ]]>
