T09 · Insecure Skill Coding Practices
- Location
bin/run.mjs:226- Finding
API Token Exposure Through Process Arguments and URL Query Parameters
- Content
View full analysis
Vulnerability Details
File Location:
bin/run.mjs:117-139, 226-236, 269-278; usage documented atSKILL.md:48
Vulnerability Type: API credential exposure through command-line arguments and query-string authentication
Risk Level: MediumVulnerable Code
SKILL.md:48:bash node {baseDir}/bin/run.mjs --operation "searchItemListV1" --token "$JUST_ONE_API_TOKEN" --params-json '{"keyword":"<keyword>"}'bin/run.mjs:117-139:js 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); const requestInit = { headers: { "accept": "application/json", }, method: operation.method, }; if (operation.requestBody && params.body !== undefined) { requestInit.body = JSON.stringify(params.body); requestInit.headers["content-type"] = operation.requestBody.contentType || "application/json"; } let response; try { response = await fetch(url, requestInit);bin/run.mjs:226-236: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:269-278: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); } }Technica
...[truncated 2962 chars]
- Remediation
View remediation
Remediation Suggestions
-
Stop passing secrets through command-line arguments. Read the credential directly from
process.env.JUST_ONE_API_TOKENand remove or deprecate--token.js function injectToken(operation, params) { const tokenParam = operation.parameters.find( (parameter) => parameter.name === "token" ); if (!tokenParam || params.token !== undefined) { return; } const token = process.env.JUST_ONE_API_TOKEN; if (!token) { fail("JUST_ONE_API_TOKEN is required.", { operationId: operation.operationId, }); } params.token = token; } -
Prefer header-based authentication. If supported by JustOneAPI, remove
tokenfrom query parameters and send it in the provider's documented authentication header, such as:js requestInit.headers.authorization = `Bearer ${token}`;The exact header and scheme must match the provider's official authentication specification.
-
Prevent token injection through
--params-json. Reject sensitive authentication fields supplied as ordinary parameters and source credentials only from the dedicated protected mechanism.js if (Object.prototype.hasOwnProperty.call(params, "token")) { fail('Do not provide "token" through --params-json.'); } -
If query authentication is mandatory, minimize secondary exposure. Never print or log the complete request URL, configure proxies and observability systems to redact the
tokenquery parameter, disable query-string capture where feasible, and apply short token lifetimes and narrowly scoped permissions. -
Update
SKILL.md. Replace the--tokenexample with an environment-only invocation and explicitly state that credentials must not be included in--params-json. -
Rotate potentially exposed credentials. Revoke and replace tokens previously used through c ...[truncated 109 chars]
-
