Detecting Org Takeover and Privilege Escalation in GitHub Audit Logs
Why this matters
A GitHub organization is source code, CI/CD credentials, and deploy keys in one place, so an owner-account compromise is a supply-chain event, not just a repo problem. The takeover playbook is consistent and every step is logged: weaken the org’s security posture (disable the 2FA requirement), establish persistence (add a member you control, mint a personal access token), plant a way to exfiltrate on every push (a webhook), and optionally destroy repositories to cover tracks or extort. Each action is individually rare and administratively significant, which is exactly why the sequence stands out when someone actually reads the log.
Indicators to look for in GitHub audit logs
action: two_factor_authentication.disabled— the 2FA requirement being turned off at the org levelaction: repo.destroyon a business-critical repository, especially from an unfamiliaractoraction: org.add_memberadding an account that does not map to a known employee (our sample addsnew-backdoor-account)action: hook.createpointing at an external URL rather than a known CI/CD or internal endpointaction: personal_access_token.createoroauth_application.createestablishing programmatic persistence- Several high-risk actions from one
actorin a tight window, sometimes across changingactor_ipvalues (our sample moves from185.220.101.42to45.142.212.100)
How LogTriage detects this
The GitHub audit parser normalizes each event into a scored action: high-risk actions (repo.destroy, two_factor_authentication.disabled, org.add_member, hook.create, and the rest of the set) map to a 403, ordinary repo./org./team. actions to a 401, and routine reads to a 200. That means a takeover sequence surfaces as a cluster of 403-scored administrative actions from one actor rather than a single ambiguous line. Each actor_ip is also checked against LogTriage’s confirmed-malicious CIDR set and live IP reputation — the sample’s 185.220.101.42 is a known Tor exit already in the IOC table, and a confirmed-malicious verdict from any one source floors that event’s risk score to 75. The published Sigma rule LTR-0014, GitHub org takeover, encodes this action sequence and is validated against the sample attack and benign logs.
Detection / evidence checklist
- Alert on
two_factor_authentication.disabledas a standalone high-severity event — it has almost no legitimate unscheduled use - List every
org.add_memberand match each new member to a real employee and an approved request - Inspect every
hook.createtarget URL; treat any unfamiliar external endpoint as active source-code exfiltration - Audit
personal_access_token.createandoauth_application.createfor tokens the org did not authorize, and revoke them - Correlate the
actorandactor_ipacross the window to establish the full blast radius of the compromised account - For any
repo.destroy, confirm whether it was cleanup or destruction, and restore from backup if the latter
Frequently Asked Questions
- What is the most dangerous single action in a GitHub org audit log?
- two_factor_authentication.disabled at the organization level. Turning off the 2FA requirement weakens every account's recovery path at once and is almost never a routine change. In our sample attack sequence it comes right after a repo.destroy and right before a backdoor org.add_member — the classic weaken-then-persist pattern of an org takeover.
- Why is hook.create a privilege-escalation and exfiltration signal?
- A webhook fires on every push and can stream source code to an attacker-controlled endpoint, giving persistent read access to the repository even after the intrusion is noticed. The audit log records hook.create with the actor and repo, so the review question is whether the webhook target is a known internal system or an unfamiliar external URL.
- Does LogTriage need the Enterprise audit log or does the org audit log work?
- Either. The parser keys on action, actor, created_at, and one of org/repo/business, which are present in both the organization audit log and the Enterprise audit stream. It accepts a JSON array or NDJSON, and reads actor_ip when the export includes it (Enterprise exports typically do).
- What actions does the parser treat as high risk?
- The high-risk set includes repo.destroy, org.add_member, org.remove_member, two_factor_authentication.disabled, hook.create, hook.destroy, oauth_application.create, personal_access_token.create, and audit_log_streaming.destroy — the actions that grant access, plant persistence, or disable the audit trail itself.
Related Resources
See this detection run on a real report
Try the live demo with a pre-loaded malicious log set — no signup required — or upload your own log file and get a full AI-reviewed threat report in minutes.