T09 · Insecure Skill Coding Practices
Warning
- Location
- bin/run.mjs:18
- Finding
- API Token Exposed Through Process Arguments and URL Query Parameters## Vulnerability Details **File Location**: `bin/run.mjs:18-24, 202-205, 236-244, 278-284`; documented usage in `SKILL.md:45-53` **Vulnerability Type**: API credential exposure through command-line arguments and URL query strings **Risk Level**: Medium ### Vulnerable Code `bin/run.mjs:18-24` defines the authentication token as a query parameter: ```js { "defaultValue": null, "description": "User authentication token.", "enumValues": [], "location": "query", "name": "token", "required": true, "schemaType": "string" }, ``` `bin/run.mjs:202-205` reads the secret from a command-line argument: ```js if (flag === "--token") { parsed.token = value; index += 1; continue; } ``` `bin/run.mjs:236-244` moves the command-line token into the request parameters: ```js function injectToken(operation, params, cliToken) { const tokenParam = operation.parameters.find((parameter) => parameter.name === "token"); if (!tokenParam || params.token !== undefined) { return; } if (!cliToken) { fail("--token is required for this operation.", { operationId: operation.operationId, }); } params.token = cliToken; } ``` `bin/run.mjs:278-284` appends every query parameter, including the token, to the request URL: ```js function applyQueryParams(operation, params, url) { for (const parameter of operation.parameters.filter((item) => item.location === "query")) { const value = params[parameter.name]; if (value === undefined) { continue; } appendValue(url.searchParams, parameter.name, value); } } ``` The documented invocation in `SKILL.md:45` explicitly passes the secret through the process argument vector: ```bash node {baseDir}/bin/run.mjs --operation "gwApiDataSpGetAuthorLinkInfoV1" --token "$JUST_ONE_API_TOKEN" --params-json '{"oAu ...[truncated 2808 chars]
- Remediation
- ## Remediation Suggestions 1. Use an `Authorization` header rather than a query parameter if supported by JustOneAPI: ```js const requestInit = { method: operation.method, headers: { accept: "application/json", authorization: `Bearer ${token}`, }, }; ``` Keep the token out of `params` and explicitly prevent `token` from being appended to `url.searchParams`. 2. Read the secret directly from `process.env.JUST_ONE_API_TOKEN` instead of requiring `--token`: ```js const token = process.env.JUST_ONE_API_TOKEN; if (!token) { fail("JUST_ONE_API_TOKEN is required."); } ``` Environment variables can still be exposed in some privileged diagnostic contexts, but they avoid routine disclosure through command-line argument collection. 3. If the upstream API strictly requires query-string authentication: - Avoid accepting the token in `--params-json`. - Read it from the environment at the last possible point. - Disable or redact query-string logging on clients, proxies, gateways, tracing platforms, and the destination service. - Ensure errors never include the complete request URL. - Document the residual exposure clearly. - Use narrowly scoped, short-lived credentials where available. - Establish token rotation and revocation procedures. 4. Update `SKILL.md`, `generated/operations.json`, and `generated/operations.md` so that examples and generated metadata reflect the safer authentication mechanism. 5. Add automated tests confirming that tokens never appear in process invocation examples, standard output, standard error, exception payloads, or request URLs.
