T09 · Insecure Skill Coding Practices
- Location
src/utils/request.js:87- Finding
API Credential Exposed in URL Query Parameters
- Content
View full analysis
Vulnerability Details
File Location:
src/utils/request.js:76-98,src/utils/request.js:101-119,src/api/comment.js:20-23,src/api/detail.js:20-23,src/api/post.js:20-23,src/api/search.js:23-26
Vulnerability Type: Credential exposure through URL query parameters
Risk Level: MediumVulnerable Code
js async function postJson(path, params, data) { if (!path || typeof path !== "string") { throw new Error("path must be a non-empty string"); } if (!params || typeof params !== "object") { throw new Error("params must be an object"); } if (!data || typeof data !== "object") { throw new Error("data must be an object"); } params.skill_name = skillName(); const fullPath = `${path}?${querystring.stringify(params)}`; const jsonData = JSON.stringify(data); const options = { host: constants.BASE_URL, path: fullPath, method: "POST", headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(jsonData), }, }; return await request(options, jsonData); }API call sites explicitly place the credential in the
paramsobject:js return await postJson( "/api/xiaohongshu/detail/url", { _: Date.now(), token: token }, { url: url, limit: limit }, );The same pattern is used by the search, post, and comment API modules. Polling requests also include the token in GET parameters:
js const res = await getJson("/api/xiaohongshu/detail/info", { _: Date.now(), token: token, url: url, limit: limit, });getJsonserializes those parameters into the request URL:js async function getJson(path, params) { if (!path || typeof path !== "string") { throw new Error("path must be a non-empty string"); } if (!params || typeof params !== "object") { throw new Error("params must be an object"); } params._ = Date.n ...[truncated 2639 chars]- Remediation
View remediation
Remediation Suggestions
-
Remove
tokenfrom every query-parameter object insrc/api/search.js,detail.js,post.js, andcomment.js. -
Pass the token separately to the HTTP utility and transmit it through an authorization header:
js const options = { host: constants.BASE_URL, path: fullPath, method: "POST", headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", "Content-Length": Buffer.byteLength(jsonData), }, }; -
Ensure server-side access logs, reverse proxies, tracing systems, and error-reporting platforms redact legacy
tokenquery parameters. -
Do not include credentials in thrown errors, telemetry, debug output, or structured result objects.
-
Rotate existing API tokens if URLs containing them may already have been retained.
-
Add automated tests asserting that generated request paths never contain
token=, while the authorization header is present. -
Consider short-lived, revocable credentials with narrowly scoped permissions to reduce the impact of future disclosure.
-
