Unusual access to GitHub by new or inactive accounts may indicate compromised credentials or adversary reconnaissance. SOC teams should proactively hunt for this behavior to identify potential credential theft or lateral movement in their Azure Sentinel environment.
KQL Query
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let LearningPeriod = 7d;
let EndLearningTime = starttime - LearningPeriod;
let GitHubActorLogin = (GitHubAudit
| where Actor != "");
let GitHubUser = (GitHubAudit
| where ImpactedUser != "");
let GitHubNewActorLogin = (GitHubActorLogin
| where TimeGenerated between (EndLearningTime .. starttime)
| summarize makeset(Actor)
| extend Dummy = 1
| join kind=innerunique (
GitHubActorLogin
| where TimeGenerated between (starttime .. endtime)
| distinct Actor
| extend Dummy = 1
) on Dummy
| project-away Dummy
| where set_Actor !contains Actor);
let GitHubNewUser = ( GitHubUser
| where TimeGenerated between (EndLearningTime .. starttime)
| summarize makeset(ImpactedUser)
| extend Dummy = 1
| join kind=innerunique (
GitHubUser
| where TimeGenerated between (starttime .. endtime)
| distinct ImpactedUser
| extend Dummy = 1
) on Dummy
| project-away Dummy
| where set_ImpactedUser !contains ImpactedUser);
union GitHubNewActorLogin, GitHubNewUser
id: b8508e24-47a6-4f8e-9066-3cc937197e7f
name: GitHub Inactive or New Account Access or Usage
description: |
'This hunting query identifies Accounts that are new or inactive and have accessed or used GitHub that may be a sign of compromise.'
requiredDataConnectors: []
tactics:
- Persistence
relevantTechniques:
- T1136
query: |
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let LearningPeriod = 7d;
let EndLearningTime = starttime - LearningPeriod;
let GitHubActorLogin = (GitHubAudit
| where Actor != "");
let GitHubUser = (GitHubAudit
| where ImpactedUser != "");
let GitHubNewActorLogin = (GitHubActorLogin
| where TimeGenerated between (EndLearningTime .. starttime)
| summarize makeset(Actor)
| extend Dummy = 1
| join kind=innerunique (
GitHubActorLogin
| where TimeGenerated between (starttime .. endtime)
| distinct Actor
| extend Dummy = 1
) on Dummy
| project-away Dummy
| where set_Actor !contains Actor);
let GitHubNewUser = ( GitHubUser
| where TimeGenerated between (EndLearningTime .. starttime)
| summarize makeset(ImpactedUser)
| extend Dummy = 1
| join kind=innerunique (
GitHubUser
| where TimeGenerated between (starttime .. endtime)
| distinct ImpactedUser
| extend Dummy = 1
) on Dummy
| project-away Dummy
| where set_ImpactedUser !contains ImpactedUser);
union GitHubNewActorLogin, GitHubNewUser
Scenario: A system administrator creates a new GitHub account to set up a CI/CD pipeline using GitHub Actions for a newly onboarded project.
Filter/Exclusion: Exclude accounts created within the last 7 days or associated with GitHub Actions workflows.
Scenario: A developer uses GitHub CLI to clone a repository and push code to a new branch, which triggers the rule due to the account being newly registered.
Filter/Exclusion: Exclude activity related to GitHub CLI or repositories with known development workflows.
Scenario: A scheduled job runs via Jenkins or GitLab CI that authenticates with a GitHub API token to fetch code updates, leading to account access.
Filter/Exclusion: Exclude API calls from CI/CD tools like Jenkins, GitLab CI, or GitHub Actions.
Scenario: An IT admin uses GitHub Enterprise to manage user access and creates a temporary account for a short-term project, which is flagged as new.
Filter/Exclusion: Exclude accounts associated with GitHub Enterprise or created for administrative tasks.
Scenario: A developer uses VS Code with the GitHub extension to sync code, which results in account access activity being flagged.
Filter/Exclusion: Exclude activity from VS Code or GitHub extensions used for development workflows.