Detection rules › Kusto
Tailscale: Tailnet lock validation failed
Identifies tailnet devices with a non-empty TailnetLockError, indicating the device failed tailnet-lock cryptographic validation. Suspicious - likely an unsigned node attempting to join.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Persistence | |
| Stealth | |
| Defense Impairment | |
| Credential Access |
Rule body
id: e9f0a1b2-3456-7890-12cd-ef1234560040
name: "Tailscale: Tailnet lock validation failed"
description: Identifies tailnet devices with a non-empty TailnetLockError, indicating the device failed tailnet-lock cryptographic validation. Suspicious - likely an unsigned node attempting to join.
description-detailed: |
Identifies tailnet devices with a non-empty TailnetLockError, indicating the device failed tailnet-lock cryptographic validation. Tailnet lock requires new node-keys be co-signed by trusted signers; errors here are the only direct signal of a node-key injection attempt.
severity: High
status: Available
requiredDataConnectors:
- connectorId: TailscaleCCF
dataTypes:
- Tailscale_Devices_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
- InitialAccess
relevantTechniques:
- T1556
- T1078
query: |
Tailscale_Devices_CL
| where TimeGenerated > ago(1h)
| summarize arg_max(TimeGenerated, *) by DeviceId
| where isnotempty(TailnetLockError)
| project TimeGenerated, DeviceName, Hostname, User, Os, ClientVersion, TailnetLockError, TailnetLockKey, LastSeen, Authorized
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: Hostname
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: User
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: P1D
matchingMethod: AllEntities
kind: Scheduled
version: 1.0.0
Stages and Predicates
Stage 1: source
Tailscale_Devices_CL
Stage 2: where
| where TimeGenerated > ago(1h)
Stage 3: summarize
| summarize arg_max(TimeGenerated, *) by DeviceId
Stage 4: where
| where isnotempty(TailnetLockError)
Stage 5: project
| project TimeGenerated, DeviceName, Hostname, User, Os, ClientVersion, TailnetLockError, TailnetLockKey, LastSeen, Authorized
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
TailnetLockError | is_not_null | field:"TailnetLockError" kind:is_not_null |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Authorized | project |
ClientVersion | project |
DeviceName | project |
Hostname | project |
LastSeen | project |
Os | project |
TailnetLockError | project |
TailnetLockKey | project |
TimeGenerated | project |
User | project |