T09 · Insecure Skill Coding Practices
- Location
src/utils/request.js:76- Finding
API Token Exposed in URL Query Strings
- Content
View full analysis
Vulnerability Details
File Locations:
src/api/search.js:20-28src/api/search.js:52-59src/api/comment.js:17-25src/api/comment.js:46-51src/api/detail.js:20-23src/api/detail.js:46-51src/api/post.js:20-23src/api/post.js:46-51src/utils/request.js:76-98src/utils/request.js:101-119
Vulnerability Type: Credential exposure through URL query parameters
Risk Level: Medium
Classification: T09: Insecure Skill Coding PracticesVulnerable Code
Task creation includes the API token in the query-parameter object:
js async function createSearchTask(token, keyword, type, sort, time, limit) { return await withRetry( async () => { return await postJson( "/api/xiaohongshu/note-search/keyword", { _: Date.now(), token: token }, { keyword, type, sort, time, limit }, ); }, constants.CREATE_MAX_ATTEMPTS, (attempt, err) => { utils.printError( `【创建任务重试】 ${attempt + 1}/${constants.CREATE_MAX_ATTEMPTS} 次 - ${err.message}`, ); }, ); }Polling requests also include the token in their query parameters:
js const res = await getJson("/api/xiaohongshu/note-search/info", { _: Date.now(), token: token, keyword, type, sort, time, limit, });The shared request utility serializes every supplied parameter into the URL:
js async function postJson(path, params, data) { if (!path || typeof path !== "string") { throw new Error("path 必须是非空字符串"); } if (!params || typeof params !== "object") { throw new Error("params 必须是对象"); } if (!data || typeof data !== "object") { throw new Error("data 必须是对象"); } params.skill_name = skillName(); const fullPath = `${path}?${querystring.stringify(params)}`; const jsonData = JSON.stringify(data); const options = { host: constants ...[truncated 3349 chars]- Remediation
View remediation
Remediation Suggestions
-
Move authentication out of the URL. Send the credential in an HTTP authorization header:
js const options = { host: constants.BASE_URL, path: fullPathWithoutToken, method: "GET", headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, }; -
Separate credentials from ordinary request parameters. Change
getJsonandpostJsonto accept the token separately so callers cannot accidentally serialize it:js async function getJson(path, params, token) { params._ = Date.now(); const fullPath = `${path}?${querystring.stringify(params)}`; return request({ host: constants.BASE_URL, path: fullPath, method: "GET", headers: { Accept: "application/json", Authorization: `Bearer ${token}`, }, }); } -
Update every API call site. Remove
tokenfrom the parameter objects insearch.js,comment.js,detail.js, andpost.js, including both task-creation and polling requests. -
Apply defense-in-depth redaction. Configure gateways, proxies, application logs, tracing tools, and error-reporting systems to redact query parameters named
token,api_key,authorization, and similar sensitive fields. -
Avoid credential logging. Ensure debugging and error handling never serialize request options or authorization headers without redaction.
-
Rotate potentially exposed credentials. Tokens previously used by affected versions should be rotated if complete URLs may have been retained by server or infrastructure logs.
-
Reduce credential replay risk. Where supported by the service, use short-lived scoped tokens, token expiration, per-client scopes, and revocation controls.
-
Add regression tests. Assert that generated request paths never contain the token or sensitive pa ...[truncated 79 chars]
-
