Detection rules › Kusto
Speculus - Threat intelligence feed outage
'Detects when no Speculus threat intelligence indicators have been received for more than 24 hours. The Speculus indexer refreshes continuously, so a silent day usually means an expired API key, a connector misconfiguration, or a feed-side outage rather than an empty feed.'
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Impact |
Rule body
id: c4f2a8d1-6e39-4c07-b5a2-1d8e3f7c9a25
name: Speculus - Threat intelligence feed outage
description: |
'Detects when no Speculus threat intelligence indicators have been received for more than 24 hours.
The Speculus indexer refreshes continuously, so a silent day usually means an expired API key,
a connector misconfiguration, or a feed-side outage rather than an empty feed.'
severity: Informational
status: Available
requiredDataConnectors:
- connectorId: SpeculusThreatIntel
dataTypes:
- Speculus_Indicators_CL
queryFrequency: 6h
queryPeriod: 2d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Impact
relevantTechniques:
- T1565
query: |
Speculus_Indicators_CL
| summarize LastReceived = max(TimeGenerated)
| where isnull(LastReceived) or LastReceived < ago(1d)
| extend
HoursSinceLastIndicator = iff(isnull(LastReceived), long(null), datetime_diff('hour', now(), LastReceived)),
Status = iff(isnull(LastReceived), 'No data ever received in query period', 'Feed silent for more than 24 hours')
suppressionDuration: 1d
suppressionEnabled: true
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: 1d
matchingMethod: AllEntities
eventGroupingSettings:
aggregationKind: SingleAlert
customDetails:
HoursSinceLast: HoursSinceLastIndicator
Status: Status
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
Speculus_Indicators_CL
Stage 2: summarize
| summarize LastReceived = max(TimeGenerated)
Stage 3: where
| where isnull(LastReceived) or LastReceived < ago(1d)
Stage 4: extend
| extend
HoursSinceLastIndicator = iff(isnull(LastReceived), long(null), datetime_diff('hour', now(), LastReceived)),
Status = iff(isnull(LastReceived), 'No data ever received in query period', 'Feed silent for more than 24 hours')
HoursSinceLastIndicator =if
isempty(LastReceived)long(null)else
datetime_diff('hour', now(), LastReceived)Status =if
isempty(LastReceived)'No data ever received in query period'else
'Feed silent for more than 24 hours'Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
LastReceived | is_null | field:"LastReceived" kind:is_null |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
LastReceived | summarize |
HoursSinceLastIndicator | extend |
Status | extend |