T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/full-workflow.js:13
- Finding
- Hard-Coded WeChat Application Credentials<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/full-workflow.js:13-19` - `scripts/publish-existing.js:12-17` - `config/config.json:2-5` **Vulnerability Type**: Hard-coded secret and plaintext credential exposure **Risk Level**: High ### Vulnerable Code `scripts/full-workflow.js:13-19` ```javascript const config = { appID: 'wx128409576294cb9d', appSecret: '3139a3d2a930678209d8ffae5e103005', apiBase: 'https://api.weixin.qq.com', outputDir: '/root/.openclaw/wechat-publish', skillDir: '/root/.openclaw/workspace/skills/wechat-mp-toolkit' }; ``` `scripts/publish-existing.js:12-17` ```javascript const config = { appID: 'wx128409576294cb9d', appSecret: '3139a3d2a930678209d8ffae5e103005', apiBase: 'https://api.weixin.qq.com' }; ``` `config/config.json:2-5` ```json "wechat": { "appID": "wx128409576294cb9d", "appSecret": "3139a3d2a930678209d8ffae5e103005", "apiBase": "https://api.weixin.qq.com" } ``` The credentials are transmitted at `scripts/full-workflow.js:210-211`: ```javascript const tokenUrl = `${config.apiBase}/cgi-bin/token?grant_type=client_credential&appid=${config.appID}&secret=${config.appSecret}`; const tokenResponse = await axios.get(tokenUrl); ``` The same transmission occurs at `scripts/publish-existing.js:39-40`: ```javascript const tokenUrl = `${config.apiBase}/cgi-bin/token?grant_type=client_credential&appid=${config.appID}&secret=${config.appSecret}`; const tokenResponse = await axios.get(tokenUrl, { timeout: 10000 }); ``` ### Technical Analysis A concrete WeChat App ID and App Secret are embedded directly in two executable scripts and one tracked configuration file. Anyone who can obtain the Skill archive, repository, an installed copy, or retained repository history can recover the secret without executing the code. The scripts use the credential to request an access token from the official WeChat API. Sending the credential to that endpoint is necessary for the declared publishing function and do ...[truncated 1686 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Immediately revoke and rotate the exposed WeChat App Secret. 2. Review WeChat API activity for unauthorized token requests, media uploads, or draft operations. 3. Remove the credential from both scripts and `config/config.json`. 4. Purge the exposed secret from repository history and invalidate all archived copies where feasible. 5. Load credentials at runtime from protected environment variables or an operating-system secret manager. For example: ```javascript const config = { appID: process.env.WECHAT_APP_ID, appSecret: process.env.WECHAT_APP_SECRET, apiBase: 'https://api.weixin.qq.com' }; if (!config.appID || !config.appSecret) { throw new Error('WECHAT_APP_ID and WECHAT_APP_SECRET are required'); } ``` 6. Commit only a sanitized example file such as `config/config.example.json`, and exclude the real credential file through `.gitignore`. 7. Restrict secret-file permissions to the account that runs the Skill. 8. Prevent secrets and access tokens from being written to application logs, exception output, telemetry, or diagnostics. 9. Apply WeChat-side least-privilege controls, including IP allowlisting and the minimum API permissions required for draft publishing. 10. Add automated secret scanning to development and release workflows. ]]>
