GitHub Audit Log IAM Privilege Escalation

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 level
  • action: repo.destroy on a business-critical repository, especially from an unfamiliar actor
  • action: org.add_member adding an account that does not map to a known employee (our sample adds new-backdoor-account)
  • action: hook.create pointing at an external URL rather than a known CI/CD or internal endpoint
  • action: personal_access_token.create or oauth_application.create establishing programmatic persistence
  • Several high-risk actions from one actor in a tight window, sometimes across changing actor_ip values (our sample moves from 185.220.101.42 to 45.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.disabled as a standalone high-severity event — it has almost no legitimate unscheduled use
  • List every org.add_member and match each new member to a real employee and an approved request
  • Inspect every hook.create target URL; treat any unfamiliar external endpoint as active source-code exfiltration
  • Audit personal_access_token.create and oauth_application.create for tokens the org did not authorize, and revoke them
  • Correlate the actor and actor_ip across 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.