T09 · Insecure Skill Coding Practices
- Location
bin/run.mjs:87- Finding
API Token Exposed Through Command-Line Arguments and URL Query Parameters
- Content
View full analysis
Vulnerability Details
File Location:
bin/run.mjs:87-111,bin/run.mjs:151-175,bin/run.mjs:199-210, andbin/run.mjs:242-264; documented usage atSKILL.md:43-49
Vulnerability Type: Sensitive credential exposure through process arguments and URL query data
Risk Level: MediumThe Skill requires an API credential for its declared IMDb plot-summary functionality. Sending authentication information to the fixed JustOneAPI endpoint is necessary, but exposing the token through both the command line and request URL exceeds the minimum-risk authentication design.
Vulnerable Code
The documented invocation passes the secret as a command-line argument:
bash node {baseDir}/bin/run.mjs --operation "titlePlotQuery" --token "$JUST_ONE_API_TOKEN" --params-json '{"id":"<id>"}'The helper parses the token directly from the process argument vector:
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; }It then places the token into the same parameter object used to construct query 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: operat ...[truncated 4466 chars]- Remediation
View remediation
Remediation Suggestions
- Remove the
--tokenargument and read the credential directly fromprocess.env.JUST_ONE_API_TOKENinside the Node.js process. This prevents routine command-line inspection from revealing the value. - Prefer an authentication header supported by the service, such as
Authorization: Bearer ..., rather than a query parameter. - If the upstream API only supports query-string authentication, request or implement a header-based authentication option. Until then, configure clients, reverse proxies, gateways, and server logging systems to redact the
tokenparameter. - Ensure errors and diagnostics never serialize the complete request URL or parameter object after token injection.
- Reject
tokeninside--params-jsonso callers cannot bypass the intended secret-loading mechanism. - Use narrowly scoped, short-lived tokens where supported, rotate any token suspected of appearing in process or URL logs, and apply account-level rate and billing alerts.
- Update
SKILL.mdso the example invokes the helper without a token argument:
bash JUST_ONE_API_TOKEN="$JUST_ONE_API_TOKEN" \ node {baseDir}/bin/run.mjs \ --operation "titlePlotQuery" \ --params-json '{"id":"<id>"}'The implementation should then obtain the value through
process.env.JUST_ONE_API_TOKENand place it in a protected authentication header.- Remove the
