webhook-development
Facilitates the development of robust webhook systems for event-driven integrations, ensuring reliable delivery and security.
Install this skill
Security score
The webhook-development skill was audited on Feb 12, 2026 and we found 112 security issues across 3 threat categories. Review the findings below before installing.
Categories Tested
Security Issues
Template literal with variable interpolation in command context
| 106 | id: `evt_${Date.now()}`, |
Template literal with variable interpolation in command context
| 159 | throw new Error(`HTTP ${response.status}`); |
Template literal with variable interpolation in command context
| 228 | id: `evt_test_${Date.now()}`, |
Webhook reference - potential data exfiltration
| 2 | name: webhook-development |
Webhook reference - potential data exfiltration
| 3 | description: Implement webhook systems for event-driven integration with retry logic, signature verification, and delivery guarantees. Use when creating event notification systems, integrating with ex |
Webhook reference - potential data exfiltration
| 6 | # Webhook Development |
Webhook reference - potential data exfiltration
| 10 | Build reliable webhook systems with event delivery, signature verification, retry logic, and dead-letter handling for asynchronous integrations. |
Webhook reference - potential data exfiltration
| 23 | ### 1. **Webhook Event Schema** |
Webhook reference - potential data exfiltration
| 50 | ### 2. **Node.js Webhook Service** |
Webhook reference - potential data exfiltration
| 61 | const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET; |
Webhook reference - potential data exfiltration
| 62 | const webhookQueue = new Bull('webhooks', { |
Webhook reference - potential data exfiltration
| 66 | // Register webhook subscription |
Webhook reference - potential data exfiltration
| 67 | app.post('/api/webhooks/subscribe', async (req, res) => { |
Webhook reference - potential data exfiltration
| 77 | const webhook = { |
Webhook reference - potential data exfiltration
| 88 | await WebhookSubscription.create(webhook); |
Webhook reference - potential data exfiltration
| 91 | id: webhook.id, |
Webhook reference - potential data exfiltration
| 92 | secret: webhook.secret, |
Webhook reference - potential data exfiltration
| 93 | message: 'Webhook registered successfully' |
Webhook reference - potential data exfiltration
| 97 | // Send webhook event |
Webhook reference - potential data exfiltration
| 98 | const sendWebhookEvent = async (eventType, data) => { |
Webhook reference - potential data exfiltration
| 99 | const webhooks = await WebhookSubscription.find({ |
Webhook reference - potential data exfiltration
| 104 | for (const webhook of webhooks) { |
Webhook reference - potential data exfiltration
| 116 | await webhookQueue.add( |
Webhook reference - potential data exfiltration
| 117 | { webhook, event }, |
Webhook reference - potential data exfiltration
| 130 | // Process webhook queue |
Webhook reference - potential data exfiltration
| 131 | webhookQueue.process(async (job) => { |
Webhook reference - potential data exfiltration
| 132 | const { webhook, event } = job.data; |
Webhook reference - potential data exfiltration
| 135 | const signature = generateSignature(event, webhook.secret); |
Webhook reference - potential data exfiltration
| 137 | const response = await axios.post(webhook.url, event, { |
Webhook reference - potential data exfiltration
| 140 | 'X-Webhook-Signature': signature, |
Webhook reference - potential data exfiltration
| 141 | 'X-Webhook-ID': event.id, |
Webhook reference - potential data exfiltration
| 142 | 'X-Webhook-Attempt': event.attempt |
Webhook reference - potential data exfiltration
| 149 | await WebhookDelivery.create({ |
Webhook reference - potential data exfiltration
| 150 | webhookId: webhook.id, |
Webhook reference - potential data exfiltration
| 167 | webhookId: webhook.id, |
Webhook reference - potential data exfiltration
| 175 | webhook.failureCount++; |
Webhook reference - potential data exfiltration
| 176 | if (webhook.failureCount >= 10) { |
Webhook reference - potential data exfiltration
| 177 | webhook.active = false; |
Webhook reference - potential data exfiltration
| 179 | await webhook.save(); |
Webhook reference - potential data exfiltration
| 184 | // Webhook endpoint (receiving webhooks) |
Webhook reference - potential data exfiltration
| 185 | app.post('/webhooks/:id', async (req, res) => { |
Webhook reference - potential data exfiltration
| 186 | const signature = req.headers['x-webhook-signature']; |
Webhook reference - potential data exfiltration
| 187 | const webhookId = req.params.id; |
Webhook reference - potential data exfiltration
| 191 | const webhook = await WebhookSubscription.findOne({ id: webhookId }); |
Webhook reference - potential data exfiltration
| 192 | if (!webhook) { |
Webhook reference - potential data exfiltration
| 193 | return res.status(404).json({ error: 'Webhook not found' }); |
Webhook reference - potential data exfiltration
| 197 | const expectedSignature = generateSignature(event, webhook.secret); |
Webhook reference - potential data exfiltration
| 203 | console.log('Received webhook event:', event); |
Webhook reference - potential data exfiltration
| 217 | // List webhook subscriptions |
Webhook reference - potential data exfiltration
| 218 | app.get('/api/webhooks', async (req, res) => { |
Webhook reference - potential data exfiltration
| 219 | const webhooks = await WebhookSubscription.find({}, { secret: 0 }); |
Webhook reference - potential data exfiltration
| 220 | res.json(webhooks); |
Webhook reference - potential data exfiltration
| 223 | // Test webhook delivery |
Webhook reference - potential data exfiltration
| 224 | app.post('/api/webhooks/:id/test', async (req, res) => { |
Webhook reference - potential data exfiltration
| 225 | const webhook = await WebhookSubscription.findOne({ id: req.params.id }); |
Webhook reference - potential data exfiltration
| 230 | event: 'webhook.test', |
Webhook reference - potential data exfiltration
| 234 | await webhookQueue.add({ webhook, event: testEvent }); |
Webhook reference - potential data exfiltration
| 240 | app.post('/api/webhooks/deliveries/:id/retry', async (req, res) => { |
Webhook reference - potential data exfiltration
| 241 | const delivery = await WebhookDelivery.findOne({ _id: req.params.id }); |
Webhook reference - potential data exfiltration
| 246 | const webhook = await WebhookSubscription.findOne({ id: delivery.webhookId }); |
Webhook reference - potential data exfiltration
| 249 | await webhookQueue.add({ webhook, event }); |
Webhook reference - potential data exfiltration
| 254 | // List webhook deliveries |
Webhook reference - potential data exfiltration
| 255 | app.get('/api/webhooks/:id/deliveries', async (req, res) => { |
Webhook reference - potential data exfiltration
| 256 | const deliveries = await WebhookDelivery.find({ |
Webhook reference - potential data exfiltration
| 257 | webhookId: req.params.id |
Webhook reference - potential data exfiltration
| 267 | // Send webhook event |
Webhook reference - potential data exfiltration
| 268 | await sendWebhookEvent('order.created', { |
Webhook reference - potential data exfiltration
| 281 | ### 3. **Python Webhook Handler** |
Webhook reference - potential data exfiltration
| 296 | class WebhookSubscription: |
Webhook reference - potential data exfiltration
| 313 | @app.route('/api/webhooks/subscribe', methods=['POST']) |
Webhook reference - potential data exfiltration
| 314 | def subscribe_webhook(): |
Webhook reference - potential data exfiltration
| 320 | webhook = WebhookSubscription( |
Webhook reference - potential data exfiltration
| 328 | db.session.add(webhook) |
Webhook reference - potential data exfiltration
| 332 | 'id': webhook.id, |
Webhook reference - potential data exfiltration
| 333 | 'secret': webhook.secret, |
Webhook reference - potential data exfiltration
| 334 | 'message': 'Webhook registered' |
Webhook reference - potential data exfiltration
| 338 | def deliver_webhook(self, webhook_id, event): |
Webhook reference - potential data exfiltration
| 339 | webhook = WebhookSubscription.query.get(webhook_id) |
Webhook reference - potential data exfiltration
| 340 | if not webhook: |
Webhook reference - potential data exfiltration
| 343 | signature = generate_signature(event, webhook.secret) |
Webhook reference - potential data exfiltration
| 347 | webhook.url, |
Webhook reference - potential data exfiltration
| 351 | 'X-Webhook-Signature': signature, |
Webhook reference - potential data exfiltration
| 352 | 'X-Webhook-ID': event['id'], |
Webhook reference - potential data exfiltration
| 353 | 'X-Webhook-Attempt': str(event.get('attempt', 1)) |
Webhook reference - potential data exfiltration
| 359 | WebhookDelivery.create( |
Webhook reference - potential data exfiltration
| 360 | webhook_id=webhook_id, |
Webhook reference - potential data exfiltration
| 373 | @app.route('/webhooks/<webhook_id>', methods=['POST']) |
Webhook reference - potential data exfiltration
| 374 | def receive_webhook(webhook_id): |
Webhook reference - potential data exfiltration
| 375 | signature = request.headers.get('X-Webhook-Signature') |
Webhook reference - potential data exfiltration
| 378 | webhook = WebhookSubscription.query.get(webhook_id) |
Webhook reference - potential data exfiltration
| 379 | if not webhook: |
Webhook reference - potential data exfiltration
| 382 | expected_signature = generate_signature(event, webhook.secret) |
Webhook reference - potential data exfiltration
| 392 | # Queue webhook delivery |
Webhook reference - potential data exfiltration
| 400 | webhooks = WebhookSubscription.query.filter( |
Webhook reference - potential data exfiltration
| 401 | WebhookSubscription.events.contains('order.created'), |
Webhook reference - potential data exfiltration
| 402 | WebhookSubscription.active == True |
Webhook reference - potential data exfiltration
| 405 | for webhook in webhooks: |
Webhook reference - potential data exfiltration
| 406 | deliver_webhook.delay(webhook.id, event) |
Webhook reference - potential data exfiltration
| 418 | - Sign all webhooks with HMAC |
Webhook reference - potential data exfiltration
| 421 | - Track webhook deliveries for debugging |
Webhook reference - potential data exfiltration
| 422 | - Provide webhook test endpoints |
Webhook reference - potential data exfiltration
| 432 | - Synchronous webhook delivery |
Webhook reference - potential data exfiltration
| 434 | - Expose webhook URLs publicly |
Webhook reference - potential data exfiltration
| 436 | - Log webhook payloads with secrets |
Webhook reference - potential data exfiltration
| 437 | - Skip webhook authentication |
Webhook reference - potential data exfiltration
| 442 | ### 5. **Webhook Events** |
Webhook reference - potential data exfiltration
| 461 | app.get('/api/webhooks/metrics', async (req, res) => { |
Webhook reference - potential data exfiltration
| 462 | const total = await WebhookDelivery.countDocuments(); |
Webhook reference - potential data exfiltration
| 463 | const delivered = await WebhookDelivery.countDocuments({ status: 'delivered' }); |
Webhook reference - potential data exfiltration
| 464 | const failed = await WebhookDelivery.countDocuments({ status: 'failed' }); |
Webhook reference - potential data exfiltration
| 465 | const avgLatency = await WebhookDelivery.aggregate([ |
Access to .env file
| 61 | const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET; |