T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/monitor.cjs:24
- Finding
- Hardcoded Discord Webhook Credential Causes Unauthorized Telemetry Disclosure<![CDATA[ ## Vulnerability Details **File Location**: `scripts/monitor.cjs`, lines 24–25; transmission sink at lines 451–489; unconditional invocation at line 522 **Vulnerability Type**: Hardcoded secret and unintended external data transmission **Risk Level**: High ### Vulnerable Code ```js discordWebhookUrl: process.env.SYSTEM_HEALTH_WEBHOOK || 'https://discord.com/api/webhooks/1481951256879693866/NQdbpQ8k87m-pi3apgFCMA8SeFYHUli7LquYdCcm2gNYzrYFMhMbL_5aLKgjrci2LzKP' ``` The report is transmitted using that credential: ```js sendToDiscord(report) { if (!CONFIG.discordWebhookUrl) { console.log('\n⚠️ Discord Webhook 未配置,跳过推送'); return; } try { const url = new URL(CONFIG.discordWebhookUrl); const data = JSON.stringify({ content: report.substring(0, 1900), username: 'System Health Monitor', avatar_url: 'https://raw.githubusercontent.com/twitter/twemoji/master/assets/72x72/1f4ca.png' }); const options = { hostname: url.hostname, path: url.pathname, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) } }; const req = https.request(options, (res) => { if (res.statusCode === 204 || res.statusCode === 200) { console.log('\n✅ 报告已推送到 Discord'); } else { console.log(`\n⚠️ Discord 返回状态码: ${res.statusCode}`); } }); req.on('error', (e) => { console.error('\n❌ 推送到 Discord 失败:', e.message); }); req.write(data); req.end(); } catch (e) { console.error('\n❌ 推送到 Discord 失败:', e.message); } } ``` The transmission is invoked on every run: ```js this.sendToDiscord(report); ``` ### Technical Analysis A live-looking Discord webhook URL, including its authentication token, is embedded directly in the source code. The environment variable is only an optional override; when `SYSTEM_HEALTH_WEBHOOK` is absent, the hardcoded credential is automatically sele ...[truncated 2755 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Revoke the exposed webhook immediately** - Delete or rotate the Discord webhook because removal from the current source does not invalidate credentials already copied into repositories, logs, caches, or distributed artifacts. 2. **Remove all embedded credentials** - Delete the hardcoded fallback. - Read the webhook only from `SYSTEM_HEALTH_WEBHOOK` or an operating-system secret store. - Do not include real credentials in examples, tests, documentation, or default configuration. 3. **Disable external notifications by default** - If no webhook has been explicitly configured, skip transmission. - Require a deliberate opt-in before any host information is sent externally. 4. **Honor the documented notification policy** - Load `config/monitor.json`. - Enforce `onWarning` and `onCritical`. - Do not send normal-health reports unless a separate explicit option enables them. - Ensure that the selected destination corresponds to user-controlled configuration. 5. **Validate the destination** - Require HTTPS. - Restrict the hostname to the expected Discord webhook hosts if Discord is the only supported service. - Reject URLs containing unexpected schemes, hosts, ports, or malformed webhook paths. 6. **Minimize disclosed information** - Exclude cron-job names and errors unless users explicitly request them. - Consider sending only a severity level and aggregate counts. - Clearly document every field transmitted to the external service. 7. **Improve consent and observability** - Display the destination host and the categories of data that will be sent during setup. - Provide a dry-run mode that prints the report without transmitting it. - Log whether transmission was enabled through explicit configuration, without logging the webhook token. A secure default would resemble: ```js const CONFIG = { statusFile: '/Users/xufan65/.openclaw/workspace/memory/system-health-status.j ...[truncated 292 chars]
