T09 · Insecure Skill Coding Practices
- Location
bin/run.mjs:206- Finding
API Token Exposed Through Command-Line Arguments and URL Query Parameters
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md:39,47;bin/run.mjs:31-38,59,206-213;generated/operations.json:16-24;generated/operations.md:20-24
Vulnerability Type: Sensitive credential exposure
Risk Level: MediumThe Skill accepts the JustOneAPI access token as a command-line argument and transmits it as a URL query parameter.
Vulnerable Code
SKILL.md:39bash node {baseDir}/bin/run.mjs --operation "getRedditPostDetailV1" --token "$JUST_ONE_API_TOKEN" --params-json '{"postId":"<postId>"}'SKILL.md:47markdown - Pass the token with `--token "$JUST_ONE_API_TOKEN"`; do not paste token values into chat messages, screenshots, or logs.bin/run.mjs:31-38js { "defaultValue": null, "description": "Access token for this API service.", "enumValues": [], "location": "query", "name": "token", "required": true, "schemaType": "string" }bin/run.mjs:59js injectToken(operation, params, args.token);bin/run.mjs:206-213js 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; }The token is subsequently processed as a query parameter:
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
Supplying a secret through
--tokencauses the shell to expand the environment variable ...[truncated 3338 chars]- Remediation
View remediation
Remediation Suggestions
-
Use authorization headers where supported. Remove
tokenfrom the query parameter manifest and send it in a dedicated header:js 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}`, }, };Use the exact header scheme required by JustOneAPI if it differs from
Bearer. -
Read the token directly from the environment. Avoid documenting or requiring
--token, which places the secret in the process argument vector. -
Reject alternate token injection. Reject
tokenin--params-jsonso callers cannot accidentally place credentials in serialized arguments or override the controlled credential source:js if (Object.prototype.hasOwnProperty.call(params, "token")) { fail("Do not provide token in --params-json."); } -
Do not log credential-bearing URLs. Ensure request, proxy, gateway, monitoring, and exception logging either omits query strings or redacts security-sensitive parameter names.
-
If the backend only supports query authentication, document this constraint explicitly, request support for header-based authentication, disable URL logging wherever possible, use narrowly scoped short-lived tokens, and rotate any token that may already have entered logs.
-
Update all generated metadata and documentation. Keep
bin/run.mjs,generated/operations.json,generated/operations.md, andSKILL.mdconsistent with the hardened authentication mechanism. -
Apply server-side least privilege. Scope tokens to only the required Reddit post-detail operation where the service supports operation-level permissions, and enforce expiration, rotation, rate limits, and anomaly monitoring.
-
