T09 · Insecure Skill Coding Practices
Warning
- Location
- bin/run.mjs:19
- Finding
- API Token Exposed Through Command-Line Arguments and URL Query Parameters<![CDATA[ ## Vulnerability Details **File Location**: `bin/run.mjs:19-27`, `bin/run.mjs:103-113`, `bin/run.mjs:173-188`, `bin/run.mjs:247-256`; related usage instructions at `SKILL.md:41` and `SKILL.md:47` **Vulnerability Type**: API credential exposure through process metadata and request URLs **Risk Level**: Medium ### Vulnerable Code The operation declares the API token as a query parameter: ```js { "defaultValue": null, "description": "API access token.", "enumValues": [], "location": "query", "name": "token", "required": true, "schemaType": "string" }, ``` The token is injected into the parameter object and all query parameters are appended to the request URL: ```js 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); ``` The command-line parser accepts the credential through `--token`: ```js function parseArgs(argv) { const parsed = { operation: null, paramsJson: "{}", token: null }; for (let index = 0; index < argv.length; index += 1) { const flag = argv[index]; const value = argv[index + 1]; if (flag === "--operation") { parsed.operation = value; index += 1; continue; } if (flag === "--params-json") { parsed.paramsJson = value; index += 1; continue; } if (flag === "--token") { parsed.token = value; index += 1; continue; } fail(`Unknown argument "${flag}".`); } return parsed; } ``` The token is copied into the parameters later serialized into the URL: ```js function injectToken(operation, params, cliToken) { const tokenParam = operation.parameters.find((parameter) => parameter.name === "token"); if (!tokenParam || params.token !== undefined) { ret ...[truncated 3120 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Remove command-line token handling** - Read the credential directly from `process.env.JUST_ONE_API_TOKEN`. - Do not support tokens in `--params-json`. - Remove or deprecate the `--token` argument so credentials are not included in process metadata. 2. **Use header-based authentication where supported** - Prefer an HTTP header such as: ```js requestInit.headers.authorization = `Bearer ${token}`; ``` - Remove `token` from the URL parameter definitions and prevent it from reaching `URL.searchParams`. - Confirm the precise authentication scheme with JustOneAPI before implementing the header. 3. **If query authentication is mandated by the upstream service** - Treat this as a documented residual risk. - Configure clients, proxies, gateways, servers, and observability systems to redact the `token` query parameter. - Never include complete request URLs in application errors or debug logs. - Use short-lived, narrowly scoped tokens where the provider supports them. - Apply strict access controls and short retention periods to URL-bearing logs. 4. **Harden input handling** - Reject a `token` property supplied through `--params-json`; otherwise callers can bypass the intended credential source. - Keep credentials separate from ordinary operation parameters throughout the request-building process. 5. **Operational controls** - Rotate any token that may already have appeared in process telemetry or URL logs. - Monitor for unusual usage, quota consumption, and access from unexpected locations. - Update `SKILL.md` so examples use the environment variable internally without expanding it into a command-line argument. ]]>
