Webhooks
Get real-time notifications when malicious prompts are detected with LockLLM webhooks.
Link to section: What Are Webhooks?What Are Webhooks?
Webhooks let you receive real-time notifications when LockLLM detects malicious prompts. Instead of polling for results, LockLLM sends HTTP POST requests to your specified URL whenever a prompt injection is detected.
Use cases:
- Security incident alerts
- Real-time monitoring dashboards
- Automated response systems
- Logging and compliance
- Integration with Slack, Discord, PagerDuty, etc.
Link to section: When Are Webhooks Triggered?When Are Webhooks Triggered?
Webhooks are triggered automatically when:
- A malicious prompt is detected (
safe: false) - In both direct API scans and proxy mode requests
- After the scan completes successfully
Webhooks are not triggered for safe prompts to reduce noise.
Link to section: Setting Up WebhooksSetting Up Webhooks
Link to section: Step 1: Create a Webhook EndpointStep 1: Create a Webhook Endpoint
Create an HTTPS endpoint that accepts POST requests:
// Express.js example
app.post('/webhooks/lockllm', async (req, res) => {
const { event, scan_result, input_preview, request_id } = req.body
if (event === 'prompt_injection_detected') {
console.log('Security Alert!')
console.log('Confidence:', scan_result.confidence)
console.log('Preview:', input_preview)
console.log('Request ID:', request_id)
// Handle the incident
await notifySecurityTeam(req.body)
}
// Always return 200 OK
res.status(200).send('OK')
})
Important: Your endpoint must:
- Use HTTPS (HTTP not supported)
- Be publicly accessible (no localhost or private IPs)
- Return HTTP 200 status code
- Respond within 1 second
Link to section: Step 2: Add Webhook in DashboardStep 2: Add Webhook in Dashboard
- Sign in to your LockLLM dashboard
- Navigate to Webhooks
- Click Add Webhook
- Enter your webhook URL (must be HTTPS)
- Select format: Raw JSON, Slack, or Discord
- Optionally add a secret for signature verification
- Optionally add a custom message
- Click Save
Link to section: Step 3: Test Your WebhookStep 3: Test Your Webhook
Test webhook delivery from the dashboard:
- Find your webhook in the list
- Click Test
- Check your endpoint receives the test payload
- Verify it returns 200 OK
Link to section: Webhook FormatsWebhook Formats
Link to section: Raw JSON FormatRaw JSON Format
Default format with complete scan data:
{
"event": "prompt_injection_detected",
"timestamp": 1705334400000,
"request_id": "req_abc123",
"user_id": "user_456",
"scan_result": {
"safe": false,
"label": 1,
"confidence": 0.95,
"injection": 0.95,
"sensitivity": "medium"
},
"input_preview": "Ignore all previous instructions and..."
}
Fields:
event: Event type (always"prompt_injection_detected"or"test"for test webhooks)timestamp: Unix timestamp in millisecondsrequest_id: Unique request identifier for trackinguser_id: Your LockLLM user IDscan_result: Complete scan resultsinput_preview: First 200 characters of the detected prompt
Link to section: Slack FormatSlack Format
Formatted for Slack incoming webhooks:
{
"text": "LockLLM flagged a prompt.",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*LockLLM flagged a prompt.*"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Status:*\nMalicious"
},
{
"type": "mrkdwn",
"text": "*Confidence:*\n95.00%"
},
{
"type": "mrkdwn",
"text": "*Injection Score:*\n0.9500"
},
{
"type": "mrkdwn",
"text": "*Request ID:*\n`req_abc123`"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Input Preview:*\n```Ignore all previous instructions and...```"
}
}
]
}
Note: The actual Slack delivery includes status indicators for visual clarity in your Slack workspace.
Setup for Slack:
- Create a Slack incoming webhook at https://api.slack.com/messaging/webhooks
- Copy the webhook URL
- Add it to LockLLM dashboard with Slack format
- Customize the message (optional)
Link to section: Discord FormatDiscord Format
Formatted for Discord webhooks:
{
"content": "LockLLM flagged a prompt.",
"embeds": [
{
"title": "Malicious Prompt Detected",
"color": 15158332,
"fields": [
{
"name": "Confidence",
"value": "95.00%",
"inline": true
},
{
"name": "Injection Score",
"value": "0.9500",
"inline": true
},
{
"name": "Request ID",
"value": "`req_abc123`",
"inline": false
},
{
"name": "Input Preview",
"value": "```Ignore all previous instructions and...```",
"inline": false
}
],
"timestamp": "2024-01-15T12:00:00.000Z"
}
]
}
Note: The embed color indicates severity (red for malicious, green for safe). The actual Discord delivery includes status indicators in the title.
Setup for Discord:
- Create a Discord webhook in your server settings
- Copy the webhook URL
- Add it to LockLLM dashboard with Discord format
- Customize the message (optional)
Link to section: Webhook SecurityWebhook Security
Link to section: HTTPS RequiredHTTPS Required
All webhook URLs must use HTTPS. HTTP is not supported for security reasons.
Link to section: Private URLs BlockedPrivate URLs Blocked
Webhooks to private or localhost URLs are blocked to prevent SSRF attacks:
localhost,127.0.0.110.0.0.0/8,172.16.0.0/12,192.168.0.0/16169.254.0.0/16(link-local)
Use a publicly accessible HTTPS endpoint.
Link to section: Signature VerificationSignature Verification
Add a secret when creating your webhook to verify authenticity:
app.post('/webhooks/lockllm', (req, res) => {
const signature = req.headers['x-lockllm-signature']
const secret = process.env.WEBHOOK_SECRET
// Verify signature matches your secret
if (signature !== secret) {
return res.status(401).send('Invalid signature')
}
// Process webhook
const { scan_result } = req.body
console.log('Verified webhook:', scan_result)
res.status(200).send('OK')
})
When you configure a secret for your webhook, it is sent in the X-LockLLM-Signature header with each request. Compare this value to your stored secret to verify the webhook originated from LockLLM.
Link to section: Retry LogicRetry Logic
LockLLM automatically retries failed webhook deliveries:
- Max retries: 3 attempts
- Backoff: Exponential (100ms × 2^attempt)
- Timeout: 1 second per attempt
- Retry conditions:
- Network errors
- Timeouts
- 5xx server errors
- 429 rate limit errors
Not retried:
- 4xx client errors (except 429)
- Invalid URLs
- HTTPS certificate errors
Link to section: Handling WebhooksHandling Webhooks
Link to section: IdempotencyIdempotency
Webhooks may be delivered more than once. Use the request_id to prevent duplicate processing:
const processedRequests = new Set()
app.post('/webhooks/lockllm', async (req, res) => {
const { request_id } = req.body
// Check if already processed
if (processedRequests.has(request_id)) {
return res.status(200).send('Already processed')
}
// Process webhook
await handleSecurityIncident(req.body)
// Mark as processed
processedRequests.add(request_id)
res.status(200).send('OK')
})
Link to section: Async ProcessingAsync Processing
Process webhooks asynchronously to respond quickly:
app.post('/webhooks/lockllm', async (req, res) => {
// Respond immediately
res.status(200).send('OK')
// Process asynchronously
setImmediate(async () => {
try {
await handleSecurityIncident(req.body)
} catch (error) {
console.error('Webhook processing failed:', error)
}
})
})
Link to section: Error HandlingError Handling
Always return 200 OK, even if processing fails:
app.post('/webhooks/lockllm', async (req, res) => {
try {
await processWebhook(req.body)
res.status(200).send('OK')
} catch (error) {
console.error('Processing error:', error)
// Still return 200 to prevent retries
res.status(200).send('Error logged')
}
})
Link to section: Managing WebhooksManaging Webhooks
Link to section: View All WebhooksView All Webhooks
See all configured webhooks in your dashboard:
- Webhook URL
- Format (Raw, Slack, Discord)
- Enabled/disabled status
- Created date
Link to section: Enable/Disable WebhooksEnable/Disable Webhooks
Temporarily disable webhooks without deleting:
- Go to Webhooks
- Find your webhook
- Toggle the enable/disable switch
Link to section: Update WebhooksUpdate Webhooks
Modify existing webhooks:
- Go to Webhooks
- Click Edit on your webhook
- Update URL, format, secret, or message
- Click Save
Link to section: Delete WebhooksDelete Webhooks
Permanently remove webhooks:
- Go to Webhooks
- Click Delete on your webhook
- Confirm deletion
Link to section: Example IntegrationsExample Integrations
Link to section: PagerDutyPagerDuty
Trigger PagerDuty incidents for high-confidence attacks:
app.post('/webhooks/lockllm', async (req, res) => {
const { scan_result, input_preview, request_id } = req.body
// High-confidence attacks trigger PagerDuty
if (scan_result.confidence > 0.9) {
await fetch('https://events.pagerduty.com/v2/enqueue', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Token token=${PAGERDUTY_TOKEN}`
},
body: JSON.stringify({
routing_key: PAGERDUTY_ROUTING_KEY,
event_action: 'trigger',
payload: {
summary: 'High-confidence prompt injection detected',
severity: 'critical',
source: 'LockLLM',
custom_details: {
confidence: scan_result.confidence,
injection_score: scan_result.injection,
request_id: request_id,
preview: input_preview
}
}
})
})
}
res.status(200).send('OK')
})
Link to section: Email AlertsEmail Alerts
Send email notifications:
const nodemailer = require('nodemailer')
app.post('/webhooks/lockllm', async (req, res) => {
const { scan_result, input_preview, request_id } = req.body
// Send email for all detections
await transporter.sendMail({
from: '[email protected]',
to: '[email protected]',
subject: 'Prompt Injection Detected',
html: `
<h2>Security Alert</h2>
<p><strong>Confidence:</strong> ${(scan_result.confidence * 100).toFixed(2)}%</p>
<p><strong>Injection Score:</strong> ${scan_result.injection.toFixed(4)}</p>
<p><strong>Request ID:</strong> ${request_id}</p>
<p><strong>Preview:</strong></p>
<pre>${input_preview}</pre>
`
})
res.status(200).send('OK')
})
Link to section: Custom LoggingCustom Logging
Log to your monitoring system:
app.post('/webhooks/lockllm', async (req, res) => {
const { scan_result, request_id, timestamp } = req.body
// Log to your system
logger.warn('prompt_injection_detected', {
request_id: request_id,
timestamp: new Date(timestamp).toISOString(),
confidence: scan_result.confidence,
injection: scan_result.injection,
sensitivity: scan_result.sensitivity
})
// Update metrics
metrics.increment('security.prompt_injection.detected')
res.status(200).send('OK')
})
Link to section: TroubleshootingTroubleshooting
Link to section: Webhook Not Receiving EventsWebhook Not Receiving Events
Problem: No webhooks are being delivered.
Solution:
- Verify webhook is enabled in dashboard
- Check your endpoint is publicly accessible
- Test the webhook from the dashboard
- Check your server logs for incoming requests
- Verify you're returning 200 OK
Link to section: "Invalid URL" Error"Invalid URL" Error
Problem: Cannot add webhook URL.
Solution:
- Ensure URL uses HTTPS (not HTTP)
- URL must be publicly accessible (no localhost)
- URL must have a valid hostname
- Check for typos in the URL
Link to section: Webhook Delivery FailuresWebhook Delivery Failures
Problem: Webhooks are failing after retries.
Solution:
- Check your endpoint responds within 1 second
- Verify endpoint returns 200 OK status
- Check server logs for errors
- Ensure HTTPS certificate is valid
- Verify no firewall blocks LockLLM IPs
Link to section: Duplicate WebhooksDuplicate Webhooks
Problem: Receiving duplicate webhook events.
Solution: Implement idempotency using request_id (see example above).
Link to section: FAQFAQ
Link to section: What are webhooks used for?What are webhooks used for?
Webhooks provide real-time notifications when malicious prompts are detected. Use them for security alerts, monitoring dashboards, incident response, logging, and integrations with Slack, Discord, or PagerDuty.
Link to section: When are webhooks triggered?When are webhooks triggered?
Webhooks are triggered automatically when a malicious prompt is detected (when safe: false). They work with both direct API scans and proxy mode requests. Safe prompts do not trigger webhooks.
Link to section: Can I use localhost for testing?Can I use localhost for testing?
No. Webhook URLs must be publicly accessible with HTTPS. For local testing, use tools like ngrok to create a public tunnel to your local server.
Link to section: What if my webhook endpoint is down?What if my webhook endpoint is down?
LockLLM automatically retries failed deliveries up to 3 times with exponential backoff. After 3 failures, the webhook delivery is abandoned. You can check webhook delivery status in your activity logs.
Link to section: How many retries are attempted?How many retries are attempted?
LockLLM retries failed webhook deliveries 3 times with exponential backoff (100ms, 200ms, 400ms). Retries are triggered by network errors, timeouts, or 5xx/429 errors.
Link to section: Can I have multiple webhooks?Can I have multiple webhooks?
Yes! You can add multiple webhook URLs for different purposes (e.g., one for Slack, one for PagerDuty, one for custom logging).
Link to section: How do I verify webhook authenticity?How do I verify webhook authenticity?
Add a secret when creating your webhook. LockLLM will include it in the X-LockLLM-Signature header. Verify this matches your secret before processing the webhook.
Link to section: What's the difference between webhook formats?What's the difference between webhook formats?
- Raw JSON: Complete data for custom processing
- Slack: Pre-formatted for Slack's block kit (incoming webhooks)
- Discord: Pre-formatted for Discord embeds
Choose based on your integration needs.