T09 · Insecure Skill Coding Practices
Warning
- Location
- bin/run.mjs:112
- Finding
- API Token Exposed Through Command-Line Arguments and URL Query Parameters<![CDATA[ ## Vulnerability Details **File Location**: `bin/run.mjs:112-147`; related invocation guidance at `SKILL.md:50-56` **Vulnerability Type**: Credential exposure through process arguments and URL query parameters **Risk Level**: Medium ### Relevant Code `bin/run.mjs:112-147`: ```javascript const args = parseArgs(process.argv.slice(2)); if (!args.operation) { fail("Missing required --operation argument."); } const operation = manifest.operations.find((item) => item.operationId === args.operation); if (!operation) { fail(`Unknown operation "${args.operation}".`, { availableOperations: manifest.operations.map((item) => item.operationId) }); } const params = parseParams(args.paramsJson); applyDefaults(operation, params); injectToken(operation, params, args.token); validateRequired(operation, params); const baseUrl = manifest.baseUrl; const url = new URL(operation.path, ensureBaseUrl(baseUrl)); applyPathParams(operation, params, url); applyQueryParams(operation, params, url); const requestInit = { headers: { "accept": "application/json", }, method: operation.method, }; if (operation.requestBody && params.body !== undefined) { requestInit.body = JSON.stringify(params.body); requestInit.headers["content-type"] = operation.requestBody.contentType || "application/json"; } let response; try { response = await fetch(url, requestInit); } catch (error) { fail("Network request failed.", { cause: error instanceof Error ? error.message : String(error), operationId: operation.operationId, }); } ``` The token is defined as a query parameter at `bin/run.mjs:24-32`: ```javascript { "defaultValue": null, "description": "User's authentication token.", "enumValues": [], "location": "query", "name": "token", "required": true, "schemaType": "string" } ``` The documented invocation at `SKILL.md:50` places the environment variable value into the process argument list: ```bash node {baseDir}/bin/run.mjs --operation "mainSe ...[truncated 3692 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Read the token directly from the environment** - Use `process.env.JUST_ONE_API_TOKEN` inside `run.mjs`. - Remove the `--token` argument so the secret is not exposed in the process command line. - Reject `token` inside `--params-json` to prevent users from accidentally placing credentials in JSON arguments. 2. **Use an authorization header** - If supported by JustOneAPI, remove `token` from the query-parameter manifest and send it in a header, for example: ```javascript const token = process.env.JUST_ONE_API_TOKEN; if (!token) { fail("JUST_ONE_API_TOKEN is required."); } const requestInit = { method: operation.method, headers: { accept: "application/json", authorization: `Bearer ${token}`, }, }; ``` 3. **Address upstream API constraints** - If JustOneAPI mandates query-string authentication, request support for header-based authentication. - Until then, document the residual logging risk, use narrowly scoped and short-lived tokens where available, and ensure URLs are redacted in proxies, telemetry, error reports, and access logs. 4. **Apply systematic redaction** - Redact parameters named `token`, `apiKey`, `authorization`, and similar variants from all diagnostics. - Never include the fully constructed request URL in errors or debug output. - Configure infrastructure logging to replace token query values with a fixed marker such as `[REDACTED]`. 5. **Rotate potentially exposed credentials** - Rotate tokens previously used through the documented command if process or URL logs may have been retained. - Review API usage for unexpected requests or quota consumption. 6. **Update the documentation** - Replace the `--token "$JUST_ONE_API_TOKEN"` example with direct environment-based execution: ```bash JUST_ONE_API_TOKEN="$JUST_ONE_API_TOKEN" \ node {baseDir}/bin/run.mjs \ --operation "mainSearchQuery" \ --params-json '{"searchTerm":"<searchTerm>"}' ``` - Prefer co ...[truncated 144 chars]
