T09 · Insecure Skill Coding Practices
- Location
index.js:73- Finding
Unauthenticated webhook enables arbitrary outbound WebSocket connections
- Content
View full analysis
{ // Respond with HTTP 200 status res.sendStatus(200); console.log('RTMS Webhook received:', JSON.stringify(req.body, null, 2)); const { event, payload } = req.body; // Handle URL validation event if (event === 'endpoint.url_validation' && payload?.plainToken) { const hash = crypto .createHmac('sha256', ZOOM_SECRET_TOKEN) .update(payload.plainToken) .digest('hex'); console.log('Responding to URL validation challenge'); return res.json({ plainToken: payload.plainToken, encryptedToken: hash, }); } // Handle RTMS started event if (event === 'meeting.rtms_started') { console.log('RTMS Started event received'); const { meeting_uuid, rtms_stream_id, server_urls, operator_id } = payload; const metadataDir = getRecordingsPath(rtms_stream_id); fs.mkdirSync(metadataDir, { recursive: true }); const metadata = { meeting_uuid, rtms_stream_id, operator_id, server_urls, start_time: new Date().toISOString(), event_ts: req.body.event_ts }; fs.writeFileSync( path.join(metadataDir, 'metadata.json'), JSON.stringify(metadata, null, 2) ); connectToSignalingWebSocket( meeting_uuid, rtms_stream_id, server_urls ); } }); ``` ```js function connectToSignalingWebSocket(meetingUuid, streamId, serverUrl) { console.log(`Connecting to signaling WebSocket for stream ${streamId}`); console.log('Stream ID:', streamId); console.log('Server URL:', serverUrl); const safeStreamId = sanitizeFileName(streamId); console.log('Sanitized Meeting UUID:', safeStreamId); const ws = new WebSocket(serverUrl); cons ...[truncated 2828 chars]- Remediation
View remediation
