T09 · Insecure Skill Coding Practices
Warning
- Location
- src/utils/request.js:105
- Finding
- API Token Transmitted in URL Query Strings<![CDATA[ ## Vulnerability Details **File Location**: - `src/api/search.js:59-62` - `src/api/search.js:104-114` - `src/api/comment.js:38-41` - `src/api/comment.js:67-73` - `src/api/post.js:23-26` - `src/api/post.js:50-55` - `src/api/hot.js:18-22` - `src/utils/request.js:94-120` - `src/utils/request.js:123-140` **Vulnerability Type**: Credential exposure through URL query parameters **Risk Level**: Medium ### Vulnerable Code The API modules add the secret token to request parameters: ```js // src/api/search.js:59-62 const params = { _: Date.now(), token: token, }; ``` The token is also included in GET requests together with user input: ```js // src/api/search.js:104-114 const params = { _: Date.now(), token: token, keyword: keyword, sort_type: sort, publish_time: time, filter_duration: duration, content_type: content, limit: limit, }; ``` The common HTTP client serializes all parameters, including the token, into the URL: ```js // src/utils/request.js:94-120 async function postJson(path, params, data) { if (!path || typeof path !== "string") { throw new SkillError("PATH_INVALID", "path 必须是非空字符串"); } if (!params || typeof params !== "object") { throw new SkillError("PARAM_INVALID", "params 必须是对象"); } if (!data || typeof data !== "object") { throw new SkillError("DATA_INVALID", "data 必须是对象"); } 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", "Accept-Encoding": "identity", "Content-Length": Buffer.byteLength(jsonData), }, }; return await request(options, jsonData); } ``` The same behavior applies to GET requests: ```js // src/utils/request.js:123-140 async function getJson(path, params) { if (!path || typeof path !== "string") { throw new SkillError("P ...[truncated 2534 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove `token` from all query-parameter objects. 2. Transmit the token in an authorization header, for example: ```js const options = { host: constants.BASE_URL, path: fullPath, method: "POST", headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", "Accept-Encoding": "identity", "Content-Length": Buffer.byteLength(jsonData), }, }; ``` 3. Refactor `getJson` and `postJson` to accept authentication separately from ordinary request parameters, preventing accidental serialization into URLs. 4. Ensure request, error, and retry logging redacts `Authorization`, cookies, tokens, and other sensitive headers. 5. Configure the API server, proxies, and monitoring systems not to record credentials or other sensitive query data. 6. Rotate tokens that may already have appeared in URL logs. 7. Prefer short-lived, scoped tokens with explicit rate and permission limits. 8. Add automated tests asserting that generated request paths never contain `token`, `api_key`, or equivalent secret parameters. ]]>
