T09 · Insecure Skill Coding Practices
Warning
- Location
- bin/run.mjs:222
- Finding
- API Token Exposure Through Command-Line Arguments and URL Query Parameters<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:40,48`; `bin/run.mjs:21-29,80-91,222-230` **Vulnerability Type**: Credential exposure through process arguments and URL query strings **Risk Level**: Medium ### Vulnerable Code `SKILL.md:40`: ```bash node {baseDir}/bin/run.mjs --operation "getUserPublishedPostsV1" --token "$JUST_ONE_API_TOKEN" --params-json '{"uid":"<uid>"}' ``` `bin/run.mjs:21-29`: ```js { "defaultValue": null, "description": "API access token.", "enumValues": [], "location": "query", "name": "token", "required": true, "schemaType": "string" } ``` `bin/run.mjs:80-91`: ```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); ``` `bin/run.mjs:222-230`: ```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); } } ``` ### Technical Analysis The Skill accepts the JustOneAPI access token through the `--token` command-line option and injects it into the request parameters. Because the manifest defines `token` as a query parameter, `applyQueryParams` appends the credential to the request URL before `fetch` sends the request to `https://api.justoneapi.com`. Passing a secret through a command-line argument can expose it through process listings, process inspection interfaces, shell auditing, command-execution telemetry, or wrapper logs. Although shell expansion of an environment variable prevents the literal token from being stored in the documented command itself, the expanded value is ...[truncated 2065 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Read the token directly from `process.env.JUST_ONE_API_TOKEN` rather than requiring it through `--token`. This prevents routine exposure through the process argument vector. 2. Prefer an authentication header supported by the service, such as: ```js const token = process.env.JUST_ONE_API_TOKEN; if (!token) { fail("JUST_ONE_API_TOKEN is required."); } const requestInit = { headers: { accept: "application/json", authorization: `Bearer ${token}`, }, method: operation.method, }; ``` 3. Remove `token` from the operation's query-parameter schema so generic query construction cannot append the secret to the URL. 4. If the upstream API only supports query-string authentication: - Still read the token directly from the environment. - Ensure clients, proxies, gateways, and application servers redact the `token` parameter. - Never print or serialize the complete request URL. - Disable URL capture in tracing and error-reporting systems where possible. - Use short-lived, narrowly scoped tokens with strict rate and spending limits. 5. Update `SKILL.md` to remove the `--token` example and document secure environment-based credential loading. 6. Rotate any token that may already have appeared in command history, process telemetry, or URL logs. ]]>
