T09 · Insecure Skill Coding Practices
Error
- Location
- src/cli/index.js:779
- Finding
- Gateway Authentication Token Exposed in Query Strings and Standard Output<![CDATA[ ## Vulnerability Details **File Location**: `src/cli/index.js:779-787` and `src/cli/index.js:916-917` **Vulnerability Type**: `T09: Insecure Skill Coding Practices` **Risk Level**: High ### Vulnerable Code ```js process.stdout.write(`${JSON.stringify({ ok: true, mode: 'gateway-agent-loop', role, agentId, decisionEngine, gateway, pullUrl: registration.pullUrl ?? `${gateway}/agents/pull?agentId=${encodeURIComponent(agentId)}&token=${encodeURIComponent(token)}` })}\n`); ``` The token is also included in every polling URL: ```js const pullUrl = `${gateway}/agents/pull?agentId=${encodeURIComponent(agentId)}&token=${encodeURIComponent(token)}&timeoutMs=${pullTimeoutMs}`; const pull = await fetchJsonOrThrow(pullUrl); ``` ### Technical Analysis The gateway registration token is used as a bearer credential but is embedded in the query string of the polling URL. The generated credential-bearing URL is then printed to standard output when the agent starts. Secrets in query strings can be captured by gateway access logs, reverse proxies, network monitoring products, tracing systems, exception diagnostics, and other URL-oriented telemetry. Printing the URL further exposes the token to terminal capture, CI logs, process supervisors, and applications consuming the CLI output. The gateway is configurable and the implementation does not require TLS. Although the documented default is a loopback HTTP endpoint, configuring a non-loopback `http://` gateway would transmit the token and negotiation traffic without transport encryption. The network communication itself is necessary for the declared gateway-only negotiation functionality. Transmitting and logging the credential in a URL is not necessary and exceeds safe least-exposure practices. ### Attack Path 1. An operator starts the gateway agent loop. 2. The gateway returns an authentication token during registration. 3. The Skill inserts that token into the `/agents/pull` query string. 4. The Sk ...[truncated 844 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove credentials from URL query parameters. 2. Transmit the token in an authorization header, for example: ```js const pullUrl = `${gateway}/agents/pull?agentId=${encodeURIComponent(agentId)}&timeoutMs=${pullTimeoutMs}`; const pull = await fetchJsonOrThrow(pullUrl, { headers: { authorization: `Bearer ${token}` } }); ``` 3. Apply the same header-based authentication design to every authenticated gateway endpoint. 4. Never print a URL received from the gateway without parsing and redacting sensitive query parameters. 5. Replace `pullUrl` in startup output with a credential-free endpoint or a redacted value. 6. Reject non-HTTPS gateway URLs unless the hostname is a verified loopback address and the operator explicitly permits local plaintext communication. 7. Configure gateway tokens with short lifetimes and narrowly scoped permissions. 8. Revoke and rotate any tokens that may already have entered logs. 9. Ensure error messages and HTTP instrumentation also redact authorization values. ]]>
