
Threat Hunter's Guide to GitHub (Datadog Security Labs)
Datadog Security Labs walks through hunting for GitHub organization compromise using GitHub audit logs, covering the full attack chain from stolen PATs/OAuth tokens and device-code phishing (initial access) through secrets-listing enumeration, private-repo/tree discovery, and bulk collection via git.clone or repo.download_zip. It provides copy-pasteable queries (with fields like hashed_token, programmatic_access_type, external_identity_nameid) mapped to MITRE ATT&CK techniques and calls out GitHub audit-log quirks (missing IP on failed auth, inconsistent visibility fields, misleading token permission scopes) that shape accurate detections.
What it is
A Datadog Security Labs threat-hunting guide (third in a series after Snowflake and Salesforce) providing verbatim GitHub audit-log queries mapped to MITRE tactics. The summary names the attack chain and the log quirks; what it cannot carry is the actual query text and the per-field/per-threshold rules that make the queries work. Those are below.
What to do
The queries use GitHub audit-log field syntax (portable to any SIEM ingesting these logs, not Datadog-only).
Initial access — login from new device/geo (T1078):
source:github
action:user.sign_in_from_unrecognized_device_and_location
actor_is_bot:falseThese events carry country code and user agent but no token type and no source IP.
Credential access — new OAuth app authorized (T1528):
source:github
action:oauth_authorization.createoauth_application_name and integration never appear in the same event; a populated integration means a user-to-server token was granted.
Discovery — secrets enumeration (T1552): match api.request against four routes (secret-scanning/alerts, actions/secrets, actions/organization-secrets, environments/:environment/secrets) with status_code:[200 TO 299], group by actor, count distinct repo over 1h. None of these expose a secret value — only that a listing occurred.
Discovery — private repo/tree walking (T1526):
source:github
action:api.request
route:("/repositories/:repository_id/git/trees"
OR /repositories/:repository_id/git/trees/*
OR /repositories/:repository_id/contents*)
-status_code>=300
-(public_repo:true OR repository_public:true OR visibility:public)For the org-repo-listing query, flag actors paging through query_string "page" values >= ~5 or in a sequential run; surface type=private in query_string separately.
Collection: action:git.clone repository_public:false and action:repo.download_zip public_repo:false. For ZIP downloads, focus on many distinct repos in under five minutes — dozens of pulls of the same repo indicate a retry loop, not theft.
The field rules that matter
These constraints, not stated in the summary, determine whether a query is correct:
- Repo visibility field depends on event type. Three fields express privacy —
public_repo,repository_public,visibility— and forapi.requestevents onlypublic_repoapplies; the others populate in other event types. A wrong field silently returns nothing. hashed_tokenis the only stable pivot.application_name/oauth_application_nameare inconsistent across event types; group byhashed_tokento follow one credential.- Token permission fields lie about scope. They describe the token's permissions in its owning org, not yours — an internet-wide scanner with admin in its own org shows admin in your log while only reading your public repos.
- Failed requests drop external identity and source IP, removing geolocation right when triaging suspicious auth.
/user/reposand EMU-only routes: those log entries exist only under GitHub Enterprise Managed Users.
To find whether private repo names/IDs have leaked, hunt route:*repositories* status_code>=400 against non-public repos, then exclude known employees by building a list of actors carrying an external_identity_nameid (present only with SSO).
Caveats
Every query needs baselining — the guide repeatedly states thresholds must be calibrated to org size (a large org may alert only at hundreds of collection attempts per 10 min). Clone/ZIP activity is inherently hard to separate from normal engineering; benign causes called out include new-laptop setup, onboarding, dev-env rebuilds, and CI runners misconfigured to use a human's PAT instead of a GitHub App.
Organisations named here
- T1078
- T1213
- T1526
- T1528
- T1552
Technologies named here
- GitHub
- Datadog Cloud SIEM
- Datadog Code Threat Detection
- GitHub Enterprise Managed Users
- GitHub integration
- OAuth
- SIEM
- GitHub Actions
- MITRE ATT&CK
Techniques named here
- Valid Accounts
- Steal Application Access Token
- Unsecured Credentials
- Cloud Service Discovery
- Data from Information Repositories
- Device code phishing
- Leaked token abuse
Also named here
- MITRE ATT&CK
Related in Blue Team & Detection
AI-Coded Malware | Analyzing Vibe-Coded AD Enumeration | Huntress
