Adversaries may delete a large number of GitHub repositories or projects to eliminate evidence or disrupt operations. SOC teams should proactively hunt for this behavior in Azure Sentinel to identify potential compromise and mitigate lateral movement or data exfiltration risks.
KQL Query
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let LearningPeriod = 7d;
let BinTime = 1h;
let EndLearningTime = starttime - LearningPeriod;
let NumberOfStds = 3;
let MinThreshold = 10.0;
let GitHubRepositoryDestroyEvents = (GitHubAudit
| where Action == "repo.destroy");
GitHubRepositoryDestroyEvents
| where TimeGenerated between (EndLearningTime .. starttime)
| summarize count() by bin(TimeGenerated, BinTime)
| summarize AvgInLearning = avg(count_), StdInLearning = stdev(count_)
| extend LearningThreshold = max_of(AvgInLearning + StdInLearning * NumberOfStds, MinThreshold)
| extend Dummy = 1
| join kind=innerunique (
GitHubRepositoryDestroyEvents
| where TimeGenerated between (starttime..endtime)
| summarize CountInRunTime = count() by bin(TimeGenerated, BinTime)
| extend Dummy = 1
) on Dummy
| project-away Dummy
| where CountInRunTime > LearningThreshold
id: 67da5c4e-49f2-476d-96ff-2dbe4b855a48
name: GitHub Mass Deletion of repos or projects
description: |
'This hunting query identifies GitHub activites where there are a large number of deletions that may be a sign of compromise.'
requiredDataConnectors: []
tactics:
- Impact
relevantTechniques:
- T1485
query: |
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let LearningPeriod = 7d;
let BinTime = 1h;
let EndLearningTime = starttime - LearningPeriod;
let NumberOfStds = 3;
let MinThreshold = 10.0;
let GitHubRepositoryDestroyEvents = (GitHubAudit
| where Action == "repo.destroy");
GitHubRepositoryDestroyEvents
| where TimeGenerated between (EndLearningTime .. starttime)
| summarize count() by bin(TimeGenerated, BinTime)
| summarize AvgInLearning = avg(count_), StdInLearning = stdev(count_)
| extend LearningThreshold = max_of(AvgInLearning + StdInLearning * NumberOfStds, MinThreshold)
| extend Dummy = 1
| join kind=innerunique (
GitHubRepositoryDestroyEvents
| where TimeGenerated between (starttime..endtime)
| summarize CountInRunTime = count() by bin(TimeGenerated, BinTime)
| extend Dummy = 1
) on Dummy
| project-away Dummy
| where CountInRunTime > LearningThreshold
Scenario: Scheduled Backup Cleanup Job
Description: A legitimate scheduled job runs nightly to clean up old or unused repositories as part of a backup or archive process.
Filter/Exclusion: Exclude activities where the user is a system admin or has a role like “Backup Admin” and the deletion is part of a known scheduled task (e.g., backup_cleanup.sh or repo_archive_job).
Scenario: User-Driven Repo Purge for Compliance
Description: A compliance officer or data governance team member is manually deleting repositories that contain outdated or sensitive data.
Filter/Exclusion: Exclude deletions initiated by users with roles like “Compliance Officer” or “Data Governance Admin” and filter by specific repository names or tags indicating compliance actions.
Scenario: CI/CD Pipeline Cleanup
Description: A CI/CD tool (e.g., GitHub Actions, Jenkins, GitLab CI) is configured to delete old build artifacts or temporary repositories after a pipeline completes.
Filter/Exclusion: Exclude deletions triggered by CI/CD runners (e.g., github-actions[bot], jenkins-bot) or repositories with names containing build, temp, or artifact.
Scenario: Admin Task for Environment Refresh
Description: An admin is performing a routine environment refresh by deleting old projects or repositories to make way for new development.
Filter/Exclusion: Exclude deletions made by users with admin privileges and where the repository name includes keywords like dev, staging, or environment-refresh.
Scenario: Merged Pull Request Cleanup
Description: After merging a pull request, a user or bot deletes the associated branch or repository as part of a cleanup process.
Filter/Exclusion: Exclude deletions where the action is triggered by a pull request merge event (e.g., `pull