T09 · Insecure Skill Coding Practices
- Location
src/auth.ts:72- Finding
Partial OAuth Refresh Token Disclosure Through Error Logging
- Content
View full analysis
Vulnerability Details
File Location:
src/auth.ts, lines 72–77
Vulnerability Type: Sensitive credential exposure through logging
Risk Level: MediumVulnerable Code
ts // Actualizar el refresh_token si ML devuelve uno nuevo if (data.refresh_token && data.refresh_token !== config.refreshToken) { process.env.ML_REFRESH_TOKEN = data.refresh_token console.error( `[ml-mcp] Refresh token actualizado. Nuevo: ${data.refresh_token.substring(0, 20)}...` ) }Technical Analysis
When Mercado Libre rotates the OAuth refresh token, the implementation writes the first 20 characters of the new token to stderr. Partial secrets remain sensitive and should not be emitted to any logging channel.
In common MCP deployments, stderr may be captured by the MCP host, process manager, container runtime, CI/CD system, or centralized logging platform. This unnecessarily distributes token material beyond the authentication component and violates least-disclosure principles.
The token refresh request itself is legitimate: credentials are sent over HTTPS to the fixed official endpoint,
https://api.mercadolibre.com/oauth/token. The vulnerability is the subsequent disclosure of part of the returned credential, not the OAuth exchange.Attack Path
- An operator configures the Skill with Mercado Libre OAuth credentials.
- The cached access token expires or approaches expiration.
- The Skill sends the refresh request to Mercado Libre.
- Mercado Libre returns a rotated refresh token.
- The Skill writes the first 20 characters of that token to stderr.
- An attacker or unauthorized operator with access to captured application logs obtains the token fragment.
- The fragment may be used for credential correlation, disclosure confirmation, or as supporting material in attacks involving another partial disclosure.
No evidence establishes that the logged fragment alone permits authentication, so full account compromise from this issue alone is ...[truncated 517 chars]
- Remediation
View remediation
Remediation Suggestions
Remove all refresh-token content from logs. Log only the outcome of the rotation:
ts if (data.refresh_token && data.refresh_token !== config.refreshToken) { process.env.ML_REFRESH_TOKEN = data.refresh_token console.error('[ml-mcp] Refresh token updated successfully.') }Apply the following additional hardening measures:
- Never log complete or partial access tokens, refresh tokens, client secrets, or authorization headers.
- Add centralized log-redaction rules for token-like values as defense in depth.
- Restrict access to MCP host, container, process-manager, and centralized logs.
- Define a short log-retention period and securely remove existing logs containing token fragments.
- Persist rotated refresh tokens in a dedicated secret manager rather than treating
process.envas durable storage. - Add automated tests that capture stderr during token rotation and assert that no token substring appears.
- Review historical logs and rotate affected credentials if token fragments have already been retained or exported.
