T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/push.js:29
- Finding
- Arbitrary Remote Host Allows Plaintext Disclosure of Tree Data and Authentication Tokens<![CDATA[ ## Vulnerability Details **File Location**: `scripts/push.js:29-53`; externally controlled parameters originate from `scripts/treelisty-cli.js:233-258` **Vulnerability Type**: Plaintext transmission of sensitive data to an unrestricted destination **Risk Level**: Medium ### Vulnerable Code ```js // scripts/treelisty-cli.js:233-258 async function cmdPush(options) { const { input, port = 3456, token, host = 'localhost' } = options; if (!input) { console.error('Error: --input is required (path to tree JSON file)'); process.exit(1); } // Check connection first console.log(`Checking TreeListy connection at ${host}:${port}...`); const status = await checkConnection({ port: parseInt(port), host }); if (!status.available) { console.error(`Cannot connect to TreeListy.`); console.error('Make sure TreeListy is open in your browser with MCP bridge enabled.'); console.error(`Reason: ${status.reason}`); process.exit(1); } console.log('Connected. Pushing tree...'); // Read and parse tree const content = readInput(input); const tree = parseJSON(content); try { const result = await push(tree, { port: parseInt(port), token, host }); ``` ```js // scripts/push.js:29-53 const { port = DEFAULT_PORT, token = null, host = 'localhost' } = options; return new Promise((resolve, reject) => { const wsUrl = `ws://${host}:${port}`; // Connection timeout const connectTimer = setTimeout(() => { ws.close(); reject(new Error(`Connection timeout - is TreeListy running with MCP bridge on port ${port}?`)); }, CONNECT_TIMEOUT); const ws = new WebSocket(wsUrl); ws.on('open', () => { clearTimeout(connectTimer); // Send handshake with token if provided const handshake = { type: 'handshake', source: 'openclaw-skill', version: '1.0.0', token: token }; ws.send(JSON.stringify(handshake)); }); ``` After the hands ...[truncated 2641 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Restrict ordinary push operations to loopback destinations: - Accept only `localhost`, `127.0.0.1`, and `::1`. - Resolve hostnames and verify that the resulting address is loopback to prevent DNS-based bypasses. 2. If remote connections are required, place them behind a separate explicit option such as `--allow-remote`. 3. Require `wss://` for every non-loopback connection and validate the server certificate. 4. Allow the complete WebSocket URL to be configured safely instead of unconditionally constructing a `ws://` URL. 5. Display a clear confirmation before sending a tree or token to a remote destination. 6. Use short-lived, narrowly scoped tokens and avoid placing secrets directly in command-line arguments, where they may appear in shell history or process listings. 7. Document the exact network behavior and update claims that imply the push function is restricted to localhost. 8. Consider applying destination allowlists and limits on tree size before transmission. ]]>
