T09 · Insecure Skill Coding Practices
Error
- Location
- src/config.js:112
- Finding
- Sensitive credentials are stored in an insufficiently protected configuration file<![CDATA[ ## Vulnerability Details **File Location**: - `src/config.js:112-116` - `commands/init.js:118-120` - `commands/init.js:145-150` - `commands/account.js:19-24` **Vulnerability Type**: Plaintext credential storage with insufficient filesystem protection **Risk Level**: High ### Vulnerable Code `src/config.js:112-116`: ```js try { fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf-8'); console.log(`✓ Configuration saved: ${CONFIG_FILE}`); return true; } catch (error) { ``` `commands/init.js:118-120`: ```js config.feishu.appToken = feishuAnswers.appToken; config.feishu.tableId = feishuAnswers.tableId; config.feishu.webhookUrl = feishuAnswers.webhookUrl; ``` `commands/init.js:145-150`: ```js config.tiktok.apiKey = apiAnswers.apiKey; config.tiktok.apiSecret = apiAnswers.apiSecret; config.tiktok.shopId = apiAnswers.shopId; } // Save configuration saveConfigFromSrc(config); ``` `commands/account.js:19-24`: ```js addAccountConfig({ username: options.username, region: options.region, cookie: options.cookie, addedAt: new Date().toISOString() }); ``` ### Technical Analysis The initialization workflow inserts TikTok API credentials and Feishu credentials directly into the general configuration object. Account creation also inserts a reusable TikTok session cookie into that object. The complete configuration is then serialized in plaintext to: ```text ~/.clawhub/tiktok-shop/config.json ``` The `saveConfig()` function does not assign restrictive permissions to either the configuration directory or the resulting file. Consequently, the effective permissions depend on the process umask and pre-existing filesystem state. On systems with permissive defaults, other local users or processes may be able to read the credentials. The project contains a separate `saveCredentials()` function that applies mode `0600` on non-Windows platforms, but the initialization and account-management paths do not use it. This defeats the intended ...[truncated 1855 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove all secrets from the general configuration object: - TikTok API keys and secrets - Session cookies - Feishu application tokens - Feishu webhook URLs 2. Store credentials using an operating-system credential manager where available, such as: - macOS Keychain - Windows Credential Manager - Linux Secret Service - A dedicated secrets-management service for server deployments 3. If file-based storage is unavoidable: - Create `~/.clawhub/tiktok-shop` with mode `0700`. - Atomically create the credentials file with mode `0600`. - Verify permissions every time credentials are loaded. - Reject symlinks and unexpected file ownership. - Avoid relying solely on a post-write `chmod`, which leaves a race window. 4. Update initialization and account creation to call the protected credential-storage API rather than `saveConfig()`. 5. Ensure `exportConfig()` excludes or redacts all sensitive values. 6. Add a migration routine that: - Reads existing sensitive fields from `config.json`. - Writes them to protected storage. - Removes them from `config.json`. - Rotates credentials if insecure permissions are detected. 7. Add automated tests verifying that secret files are owner-readable only and that exported configuration never includes credentials. ]]>
