T09 · Insecure Skill Coding Practices
- Location
src/utils/log.js:29- Finding
Automatic Plaintext Persistence of User Queries and Collected Douyin Data
- Content
View full analysis
Vulnerability Details
File Location:
src/utils/log.js:29-35, invoked fromsrc/douyin/search-cli.js:280-283,src/douyin/post-cli.js:209-212, andsrc/douyin/comment-cli.js:198-201
Vulnerability Type: Automatic plaintext storage of potentially sensitive data
Risk Level: MediumComplete Code Snippets
The shared logging utility creates a project-local directory and writes supplied content with default filesystem permissions:
js const outputFilename = path.join( path.dirname(__filename), "..", "..", "logs", safeFilename, ); try { await fs.promises.mkdir(path.dirname(outputFilename), { recursive: true }); await fs.promises.writeFile(outputFilename, content); utils.printSuccess(` → 已保存到 ${outputFilename}`); } catch (error) { utils.printError(`日志写入失败: ${error.message}`); }Successful searches unconditionally persist the complete request and response. The keyword is also included in the filename:
js await log.taskWrite( `${startTime}_${keyword}_${sort}_${time}_${duration}_${content}_search.json`, JSON.stringify(finalOutput, null, 2), );Successful post retrievals unconditionally persist the complete result:
js await log.taskWrite( `${startTime}_${url}_post.json`, JSON.stringify(finalOutput, null, 2), );Successful comment retrievals unconditionally persist the complete result:
js await log.taskWrite( `${startTime}_${url}_comment.json`, JSON.stringify(finalOutput, null, 2), );Technical Analysis
Every successful search, post, or comment operation serializes its complete output envelope and writes it in plaintext beneath the project’s
logs/directory. Persistence is automatic: users are not required to provide an output option or explicitly consent to local retention.The saved content contains the request parameters and complete API results. Depending on the operation, this can include:
- Search keywords and research interests
- Monitored account, video, or post ident ...[truncated 2936 chars]
- Remediation
View remediation
Remediation Suggestions
-
Disable persistence by default
- Do not call
taskWrite()unless the user explicitly requests saved output. - Add an option such as
--output <path>or--save. - Keep stdout as the default and only output channel.
- Do not call
-
Obtain informed consent
- Clearly disclose which request and result fields will be retained.
- Require explicit confirmation before storing comments, identifiers, or location-related metadata.
- Correct
SKILL.mdso it accurately states that local writes occur when persistence is enabled.
-
Use restrictive file permissions
- Create the directory with a restrictive mode where supported.
- Write files with mode
0o600. - Verify that existing files are not overwritten with broader inherited permissions.
-
Minimize retained data
- Do not include raw keywords or user identifiers in filenames.
- Use a random identifier or timestamp-only filename.
- Exclude fields not required for the user’s stated purpose.
- Consider redacting commenter identifiers and IP-region information.
-
Implement lifecycle controls
- Add configurable retention periods and secure deletion.
- Provide a command to enumerate and delete saved results.
- Document backup and source-control risks.
- Add
logs/to.gitignoreif local persistence remains supported.
-
Prevent uncontrolled storage growth
- Enforce a maximum output-file size.
- Add rotation or quotas.
- Warn before persisting unusually large result sets.
-
