T09 · Insecure Skill Coding Practices
- Location
references/auth-flows.md:520- Finding
Caller-Controlled OAuth Endpoint Can Receive Confidential Client Credentials
- Content
View full analysis
Vulnerability Details
File Location:
references/auth-flows.md, lines 520-563
Vulnerability Type: Unrestricted transmission of client credentials to a caller-controlled endpoint
Risk Level: HighVulnerable Code
typescript async function getM2MToken( domain: string, clientId: string, clientSecret: string, scopes: string[] ) { const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64'); const response = await fetch(`https://${domain}/oauth2/token`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', Authorization: `Basic ${credentials}`, }, body: new URLSearchParams({ grant_type: 'client_credentials', scope: scopes.join(' '), }), }); const data = await response.json(); return data.access_token; // Only access token — no ID or refresh token }python import requests import base64 def get_m2m_token(domain: str, client_id: str, client_secret: str, scopes: list[str]): credentials = base64.b64encode(f"{client_id}:{client_secret}".encode()).decode() response = requests.post( f"https://{domain}/oauth2/token", headers={ "Content-Type": "application/x-www-form-urlencoded", "Authorization": f"Basic {credentials}", }, data={ "grant_type": "client_credentials", "scope": " ".join(scopes), }, ) return response.json()["access_token"]Technical Analysis
Base64 encoding the client ID and client secret is the standard encoding required by HTTP Basic authentication and is necessary for the Cognito client-credentials flow. It is not encryption and provides no confidentiality independently of TLS.
The security defect is that the destination
domainis accepted without validation. If this value is obtained from configuration, reque ...[truncated 1590 chars]- Remediation
View remediation
Remediation Suggestions
- Do not accept an arbitrary destination hostname at the point where credentials are transmitted.
- Construct the endpoint from trusted deployment configuration rather than request or tenant input.
- For Cognito-managed domains, validate the hostname against the expected AWS Cognito domain and region.
- For custom Cognito domains, maintain an explicit allowlist of exact hostnames.
- Parse the endpoint with a URL parser and reject user information, unexpected ports, fragments, query strings, and path confusion.
- Do not use a suffix-only hostname check that could accept names such as
amazoncognito.com.attacker.example. - Check
response.okin TypeScript and callresponse.raise_for_status()in Python before processing the body. - Validate that the returned JSON contains a correctly typed
access_token. - Set connection and response timeouts.
- Store client secrets in AWS Secrets Manager or another dedicated secret store and rotate them after suspected disclosure.
- Limit each M2M client to the minimum required custom scopes.
