Security Alerts
LogStitch detects suspicious patterns in your audit log stream in real-time. When event activity matches a detection rule, an alert fires automatically. Built-in rules cover common threats out of the box, and paid plans unlock custom rules and webhook delivery.
Overview#
Security alerts work inline during event ingestion. Every event is evaluated against all enabled rules as it arrives. Detection is fire-and-forget — it never blocks or delays event ingestion.
- An event is ingested via the API
- The detection engine checks the event against all enabled rules
- If the event matches a rule's action pattern, the engine increments a counter for the rule's group key (e.g. actor_id)
- If the counter exceeds the threshold within the sliding window, an alert fires
- If webhooks are configured, a signed POST is sent to each endpoint
Built-in Detection Rules#
LogStitch ships with six built-in detection rules. Five are enabled by default. You can toggle any rule on or off and adjust the cooldown period via the API.
| ID | Name | Action Pattern | Threshold | Group By | Severity | Default |
|---|---|---|---|---|---|---|
| auth_brute_force | Auth Brute Force | auth.failed* | 5 in 5min | actor_id | high | On |
| privilege_escalation_burst | Privilege Escalation Burst | *.role.updated | 3 in 10min | actor_id | critical | On |
| rapid_api_key_creation | Rapid API Key Creation | *.api_key.created | 3 in 5min | actor_id | medium | On |
| bulk_data_export | Bulk Data Export | *.exported | 5 in 10min | actor_id | medium | On |
| account_deletion_spike | Account Deletion Spike | *.deleted | 5 in 10min | tenant_id | high | On |
| suspicious_ip_change | Suspicious IP Change | * | 3 distinct IPs in 30min | actor_id | medium | Off |
How Detection Works#
Action Pattern Matching#
Each rule has an action_pattern that uses glob-style matching against the event's action field:
*— matches all eventsauth.failed*— matchesauth.failed,auth.failed_mfa, etc.*.deleted— matchesuser.deleted,document.deleted, etc.
Group-By Extraction#
The group_by field determines how matching events are grouped for counting. For example, grouping by actor_id means each actor has their own independent counter. A brute-force rule grouped by actor_id fires when a single actor exceeds the threshold, not when all actors combined do.
Sliding Window#
The engine uses a sliding time window. If threshold is 5 and window_seconds is 300 (5 minutes), the alert fires when 5 or more matching events from the same group arrive within any 5-minute window.
Cooldown#
After an alert fires for a given group key, the rule enters a cooldown period (default: 1 hour). During cooldown, matching events are still counted but no new alert fires for that group. This prevents alert fatigue from sustained attacks.
Managing Rules via API#
Use the Alerts API to list, toggle, and manage alert rules programmatically.
curl https://logstitch.io/api/v1/alerts/rules \
-H "Authorization: Bearer pk_..."curl -X PATCH https://logstitch.io/api/v1/alerts/rules/auth_brute_force \
-H "Authorization: Bearer mk_..." \
-H "Content-Type: application/json" \
-d '{
"enabled": false
}'curl -X PATCH https://logstitch.io/api/v1/alerts/rules/auth_brute_force \
-H "Authorization: Bearer mk_..." \
-H "Content-Type: application/json" \
-d '{
"enabled": true,
"cooldown_seconds": 7200
}'Custom Alert Rules (Paid)#
Paid plan required
Custom rules let you define your own detection logic. Specify an action pattern, threshold, window, and severity to match your application's threat model.
curl -X POST https://logstitch.io/api/v1/alerts/rules \
-H "Authorization: Bearer mk_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Bulk invite spike",
"action_pattern": "team.member.invited",
"threshold": 10,
"window_seconds": 600,
"group_by": "tenant_id",
"severity": "medium"
}'{
"rule": {
"id": "550e8400-...",
"type": "custom",
"name": "Bulk invite spike",
"action_pattern": "team.member.invited",
"threshold": 10,
"window_seconds": 600,
"group_by": "tenant_id",
"severity": "medium",
"enabled": true,
"cooldown_seconds": 3600,
"created_at": "2026-01-20T14:00:00.000Z"
},
"request_id": "req_abc123"
}Alert Lifecycle#
Every fired alert follows a three-state lifecycle:
- open — Alert has fired and requires attention
- acknowledged — A team member has seen the alert and is investigating
- resolved — The issue has been addressed
Transition alerts using the PATCH endpoint:
curl -X PATCH https://logstitch.io/api/v1/alerts/alt_01HX... \
-H "Authorization: Bearer pk_..." \
-H "Content-Type: application/json" \
-d '{ "status": "acknowledged" }'curl -X PATCH https://logstitch.io/api/v1/alerts/alt_01HX... \
-H "Authorization: Bearer pk_..." \
-H "Content-Type: application/json" \
-d '{ "status": "resolved" }'Webhooks (Paid)#
Paid plan required
When an alert fires, LogStitch sends a signed HTTP POST to each enabled webhook endpoint. The payload includes the alert details and the rule that triggered it.
Webhook Payload#
{
"type": "alert.fired",
"alert": {
"id": "alt_01HX...",
"rule_id": "auth_brute_force",
"rule_name": "Auth Brute Force",
"severity": "high",
"status": "open",
"group_key": "user_456",
"event_count": 7,
"sample_event_ids": ["evt_01HX...", "evt_01HX..."],
"fired_at": "2026-01-20T15:30:00.000Z"
},
"project_id": "proj_01HX...",
"timestamp": "2026-01-20T15:30:01.000Z"
}Signature Verification#
Every webhook request includes an X-LogStitch-Signature header containing an HMAC-SHA256 signature of the request body, signed with the webhook secret. Always verify this signature before processing the payload.
import { createHmac, timingSafeEqual } from 'crypto';
function verifyWebhookSignature(
body: string,
signature: string,
secret: string,
): boolean {
const expected = createHmac('sha256', secret)
.update(body)
.digest('hex');
return timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected),
);
}
// In your webhook handler:
const sig = req.headers['x-logstitch-signature'];
if (!verifyWebhookSignature(rawBody, sig, webhookSecret)) {
return res.status(401).send('Invalid signature');
}Retry Behavior#
If your endpoint returns a non-2xx status or times out (10 second limit), LogStitch retries up to 3 times with exponential backoff (30s, 120s, 480s). After all retries are exhausted, the delivery is marked as failed.
Dashboard#
Security alerts are also manageable from the LogStitch dashboard. The dashboard provides a visual interface for viewing fired alerts, toggling rules, and configuring webhooks. See the dashboard to get started.