T09 · Insecure Skill Coding Practices
- Location
scripts/authenticate.py:48- Finding
OAuth Refresh Token Exposed in Standard Output
- Content
View full analysis
Vulnerability Details
File Location:
scripts/authenticate.py, lines 48–52
Vulnerability Type: Plaintext sensitive-token disclosure
Risk Level: HighVulnerable Code
python # Store refresh token refresh_token = credentials.refresh_token print(f"\n{'='*60}") print(f"REFRESH TOKEN: {refresh_token}")Technical Analysis
After the OAuth authorization flow completes, the script prints the complete Google OAuth refresh token to standard output. A refresh token is a long-lived credential that can be exchanged for short-lived access tokens under the granted Google Ads scope:
text https://www.googleapis.com/auth/adwordsStandard output is not a secure secret-transfer mechanism. In agent, CI/CD, terminal-recording, debugging, or support environments, it may be captured by execution logs, monitoring systems, conversation transcripts, or session recordings. The warning printed after the token does not prevent the token from already being disclosed.
This behavior also conflicts with the security rule in
SKILL.mdthat tokens and credentials must never be exposed in files or chat.Attack Path
- A user or agent follows the documented authentication procedure and runs
python3 scripts/authenticate.py. - The user completes Google's OAuth authorization flow.
- Google returns a refresh token to the script.
- The script writes the complete refresh token to standard output.
- The execution environment retains or forwards that output through logs, agent context, terminal recording, monitoring, or support transcripts.
- An attacker with access to the captured output obtains the refresh token.
- The attacker combines it with the relevant OAuth client credentials and exchanges it at Google's token endpoint for access tokens.
- The attacker uses those access tokens to access Google Ads resources available to the authorized identity.
Impact Assessment
A disclosed refresh token can provide durable access because it may cont ...[truncated 633 chars]
- A user or agent follows the documented authentication procedure and runs
- Remediation
View remediation
Remediation Suggestions
- Remove all statements that print the refresh token or other OAuth credentials.
- Transfer the token directly to the workspace's approved secret manager instead of standard output, chat, files, or shell history.
- If direct secret-manager integration is unavailable, fail safely and provide instructions for completing credential enrollment through a trusted, non-logged channel.
- Ensure secret values are redacted from exceptions, debug logs, telemetry, and agent tool results.
- Disable verbose HTTP or OAuth debugging in production authentication workflows.
- Restrict access to authentication execution logs and configure automatic secret masking as defense in depth.
- Revoke and rotate any refresh token previously displayed by this script, then review relevant Google account and Google Ads access logs for unexpected activity.
- Add an automated test or static-analysis rule that rejects output statements containing tokens, client secrets, passwords, or similarly sensitive values.
A safer implementation should confirm success without revealing the credential, for example:
python refresh_token = credentials.refresh_token if not refresh_token: print("Error: No refresh token was returned.") sys.exit(1) # Store refresh_token directly through an approved secret-store integration. print("Authentication succeeded. The refresh token was stored securely.")
