T09 · Insecure Skill Coding Practices
- Location
src/lib/auth.ts:169- Finding
OAuth Credentials and Tokens Transmitted in URL Query Parameters
- Content
View full analysis
Vulnerability Details
File Location:
src/lib/auth.ts:169-178andsrc/lib/auth.ts:202-209
Vulnerability Type: Sensitive information exposed through request URLs
Risk Level: MediumVulnerable Code
ts const response = await got.post(`${OAUTH_BASE}/authorization/token`, { searchParams: { type: 'web_server', client_id: clientId, client_secret: clientSecret, redirect_uri: redirectUri, code, code_verifier: codeVerifier } }).json<{ access_token: string; refresh_token: string; expires_in: number }>();ts const response = await got.post(`${OAUTH_BASE}/authorization/token`, { searchParams: { type: 'refresh', client_id: clientId, client_secret: clientSecret, refresh_token: currentTokens.refresh_token } }).json<{ access_token: string; expires_in: number }>();Technical Analysis
The OAuth token exchange and refresh requests use Got's
searchParamsoption. This places the OAuth client secret, authorization code, PKCE verifier, and refresh token in the request URL query string rather than in the POST body.HTTPS encrypts the request in transit, and the destination is the expected official endpoint at
https://launchpad.37signals.com. Therefore, this behavior is not evidence of malicious credential exfiltration and is functionally required for authentication. However, placing secrets in URLs unnecessarily increases their exposure because complete URLs may be captured by:- Forward or reverse proxies
- HTTP diagnostic and tracing systems
- Application performance monitoring tools
- Exception and debug logs
- Network security appliances
- Request-history or telemetry systems
OAuth credentials should be submitted in an
application/x-www-form-urlencodedrequest body or through the authorization mechanism required by the OAuth provider. Sensitive parameters should not appear in request URLs.Att
...[truncated 1515 chars]
- Remediation
View remediation
Remediation Suggestions
-
Replace
searchParamswith Got'sformoption so OAuth parameters are encoded in the POST body:ts const response = await got.post(`${OAUTH_BASE}/authorization/token`, { form: { type: 'web_server', client_id: clientId, client_secret: clientSecret, redirect_uri: redirectUri, code, code_verifier: codeVerifier } }).json<TokenResponse>(); -
Apply the same change to the refresh-token request:
ts const response = await got.post(`${OAUTH_BASE}/authorization/token`, { form: { type: 'refresh', client_id: clientId, client_secret: clientSecret, refresh_token: currentTokens.refresh_token } }).json<RefreshResponse>(); -
If supported by the OAuth provider, authenticate the client through an appropriate authorization header instead of transmitting the client secret as a request parameter.
-
Review HTTP error handling and diagnostic logging to ensure request URLs, bodies, and headers containing OAuth credentials are redacted.
-
Rotate the OAuth client secret and revoke existing refresh tokens if URLs containing these values may already have been retained in logs.
-
