T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/card-callback-server.js:34
- Finding
- Raw Feishu Callback Data Is Forwarded by Default to a Configurable Gateway<![CDATA[ ## Vulnerability Details **File Location**: `scripts/card-callback-server.js:34-88` and `scripts/card-callback-server.js:470-494` **Vulnerability Type**: Default-enabled transmission of excessive callback data to a configurable destination **Risk Level**: Medium ### Vulnerable Code ```javascript // scripts/card-callback-server.js:34-88 function loadGatewayConfig() { try { const configPath = path.join(os.homedir(), '.openclaw', 'openclaw.json'); if (fs.existsSync(configPath)) { const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); return { url: process.env.OPENCLAW_GATEWAY_URL || config.gateway?.url || `http://localhost:${config.gateway?.port || 18789}`, token: process.env.OPENCLAW_GATEWAY_TOKEN || config.gateway?.token || '', enabled: config.gateway?.enabled !== false // enabled by default }; } } catch (error) { console.log('Unable to read OpenClaw configuration:', error.message); } return { url: process.env.OPENCLAW_GATEWAY_URL || 'http://localhost:18789', token: process.env.OPENCLAW_GATEWAY_TOKEN || '', enabled: false }; } const GATEWAY_CONFIG = loadGatewayConfig(); const GATEWAY_URL = GATEWAY_CONFIG.url; const GATEWAY_TOKEN = GATEWAY_CONFIG.token; const GATEWAY_ENABLED = GATEWAY_CONFIG.enabled && GATEWAY_TOKEN; async function sendToGateway(callbackData) { if (!GATEWAY_ENABLED) { return; } try { const payload = { type: 'feishu_card_callback', timestamp: new Date().toISOString(), data: callbackData }; await axios.post(`${GATEWAY_URL}/api/callback`, payload, { headers: { 'Authorization': `Bearer ${GATEWAY_TOKEN}`, 'Content-Type': 'application/json' }, timeout: 3000 }); } catch (error) { // Error handling omitted } } ``` ```javascript // scripts/card-callback-server.js:470-494 const eventDispatcher = new lark.EventDispatcher({ loggerLevel: lark.LoggerLevel. ...[truncated 3354 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Make Gateway forwarding explicitly opt-in: ```javascript enabled: config.gateway?.enabled === true ``` 2. Require a separate setting such as `forwardFeishuCallbacks: true` rather than inferring consent from the presence of a Gateway token. 3. Remove `raw_data` and transmit only fields required by the receiving component: ```javascript sendToGateway({ event_id, action: { value: action?.value } }); ``` 4. Redact user identifiers, form values, authorization-related fields, and unknown nested properties unless they are strictly required. 5. Parse the Gateway URL and enforce: - `https:` for remote destinations. - `http:` only for loopback addresses such as `127.0.0.1`, `::1`, or `localhost`. - An administrator-configured hostname allowlist. 6. Do not send reusable bearer tokens over plaintext connections. Use TLS certificate validation and narrowly scoped, short-lived credentials where supported. 7. Update the documentation to identify every forwarded field, the destination, the default state, retention expectations, and the procedure for disabling forwarding. 8. Apply the same changes to `scripts/card-callback-original.js` or remove that duplicate implementation to prevent operators from accidentally deploying the vulnerable version. 9. Avoid logging complete callback context because logs may create an additional sensitive-data exposure path. ]]>
