↳ GitHub sourceAnalytics ruleMedium

Brute Force Attack against GitHub Account

Description

'Attackers who are trying to guess your users' passwords or use brute-force methods to get in. If your organization is using SSO with Microsoft Entra ID, authentication logs to GitHub.com will be generated. Using the following query can help you identify a sudden increase in failed logon attempt of users.'
Rule type
Scheduled
Version
2.0.2
Declared status
Available
Query frequency
1h
Query period
7d
Trigger
gt 0

Declared MITRE coverage

Declared sources

Metadata from the source file. No dependencies inferred from KQL.

Connectors

Data types

KQL query

Original query, unchanged.

let LearningPeriod = 7d;
let BinTime = 1h;
let RunTime = 1h;
let StartTime = 1h;  
let sensitivity = 2.5;
let EndRunTime = StartTime - RunTime;
let EndLearningTime = StartTime + LearningPeriod;
let aadFunc = (tableName:string){
table(tableName)  
| where TimeGenerated between (ago(EndLearningTime) .. ago(EndRunTime))
| where AppDisplayName =~ "GitHub.com"
| where ResultType != 0
| make-series FailedLogins = count() on TimeGenerated from ago(LearningPeriod) to ago(EndRunTime) step BinTime by UserPrincipalName, Type
| extend (Anomalies, Score, Baseline) = series_decompose_anomalies(FailedLogins, sensitivity, -1, 'linefit')
| mv-expand FailedLogins to typeof(double), TimeGenerated to typeof(datetime), Anomalies to typeof(double), Score to typeof(double), Baseline to typeof(long)  
| where TimeGenerated >= ago(RunTime)
| where Anomalies > 0 and Baseline > 0
| join kind=inner (
          table(tableName)  
          | where TimeGenerated between (ago(StartTime) .. ago(EndRunTime))
          | where AppDisplayName =~ "GitHub.com"
          | where ResultType != 0
          | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), IPAddresses = make_set(IPAddress,100), Locations = make_set(LocationDetails,20), Devices = make_set(DeviceDetail,20) by UserPrincipalName, UserId, AppDisplayName
      ) on UserPrincipalName
| project-away UserPrincipalName1
| extend Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])
| extend IPAddressFirst = tostring(IPAddresses[0])
};
let aadSignin = aadFunc("SigninLogs");
let aadNonInt = aadFunc("AADNonInteractiveUserSignInLogs");
union isfuzzy=true aadSignin, aadNonInt

Declared entities

AccountIP

Related content

Links established from declared identifiers and solution manifests.

Source provenance

GitHub

Displayed values come from files in Azure/Azure-Sentinel. They describe the published template, not your workspace configuration.

Source identifier
97ad74c4-fdd9-4a3f-b6bf-5e28f4f71e06
Additional source files 3Solutions/Microsoft Entra ID/Analytic Rules/Brute Force Attack against GitHub Account.yamlsource ↗Detections/SigninLogs/Brute Force Attack against GitHub Account.yamlmigration-note ↗Solutions/Microsoft Entra ID/Data/Solution_AAD.jsonsolution-membership ↗
GSTEP / CATALOG TRACKING

Added to catalog : 16 Sept 2026 · 05:49 UTC
Last change observed : 16 Sept 2026 · 05:49 UTC

GSTEP sync dates, separate from the source content’s publication dates.