When an attacker controls an owner, a token or an app inside your GitHub organisation, they can read private code, plant workflows that steal CI secrets, and delete or ransom repositories, all under identities you trust. A GitHub org compromise is not the same as a single leaked token: you have to work out which human accounts, personal access tokens, OAuth apps, GitHub Apps and deploy keys were used, then cut them off before you clean up the damage they did. This playbook covers how the incident shows up, the triage questions for the first hours, containment in priority order, eradication of malicious commits and workflows, recovery of deleted repositories, evidence to keep and when notification rules apply. It is written for security teams, incident responders and organisation owners. Build systems in general are covered in the CI/CD Pipeline Compromise Playbook; this page stays on the GitHub organisation itself.
This is an independent guide from NHI Mgmt Group, based on GitHub's public documentation as of November 2026. It is not sponsored or reviewed by GitHub. Product features change, so confirm settings against GitHub's current documentation.
Key takeaways
- Find the credential, not just the commit. Removing a malicious workflow does nothing if the token or account that pushed it still works; the same identity will be used again.
- Owners are the recovery path. Only organisation owners can read the audit log, revoke fine-grained tokens and restore deleted repositories, so a second trusted owner is the difference between a fast and a slow response.
- SAML revocation is not deletion. Revoking a member's authorised credentials removes the SAML authorisation only; the token or SSH key still exists and must be removed by its owner or by suspending the account.
- Every reachable secret is burned. Any Actions secret a malicious workflow could reference, and any secret printed in a run log, should be treated as exfiltrated and rotated at its source.
- The clock on deleted repositories is 90 days. Owners can restore deleted organisation repositories within that window, but team permissions do not come back and fork networks can block the restore.
How the incident shows up
Most GitHub organisation compromises start with a stolen credential rather than a flaw in GitHub: a phished member who approved a malicious OAuth app, a personal access token (PAT) left in a public repository or a Docker image, a session token taken by infostealer malware, or a leaked GitHub App private key. In ATT&CK terms the entry is usually Cloud Accounts (T1078.004) or Steal Application Access Token (T1528), followed by Code Repositories (T1213.003) collection, and sometimes Data Destruction (T1485).
| Signal | Where you see it | What it often means |
|---|---|---|
New workflow files under .github/workflows pushed directly to default branches across many repositories | Commit history, workflows audit events, secret scanning or third-party alerts | Stolen member credential used to plant secret-stealing workflows |
| Repositories renamed, emptied or deleted, with a README demanding contact | repo.destroy, repo.rename audit events, user reports | Extortion using an account or OAuth app with admin rights |
| Unfamiliar OAuth app authorisations or GitHub App installations | oauth_application and integration_installation audit events | Consent phishing or persistence after a takeover |
| Cloning or API access from unusual countries or at volume | Audit log country: filter, exported git events | Bulk theft of private source code |
| A member or owner added, or a role changed, by an account that does not normally do it | org audit events | Attacker building persistence before you notice |
| Changes to organisation secrets, branch rules or Actions policy | org.update_actions_secret and repository rule events | Preparing to exfiltrate or weakening controls |
| Cloud, registry or package provider alerts about a GitHub-held credential | Provider notifications, secret scanning alerts | A secret already left your organisation |
For the event names and rules worth building ahead of time, see the GitHub Audit Log Detection Guide.
Triage questions
Answer these in the first one to two hours. Each answer changes what you contain first.
- Do you still control the owner accounts? If an owner is compromised or locked out, organisation-level actions depend on another owner. GitHub recommends at least two people hold the owner role so no one loses access.
- Which identity did the attacker use? A human account (password and session), a PAT, an OAuth app token, a GitHub App installation or a deploy key each need a different revocation step.
- Do you have the token value or only its effects? If you have the leaked value, compute its SHA-256 hash and search the audit log with the
hashed_tokenqualifier to list exactly what it did. Supported types include PATs, OAuth tokens, GitHub App tokens, and, in public preview, deploy keys and SSH keys. - Did any workflow run with secrets? Check which planted workflows actually executed, which secrets they referenced and whether runs were held for approval.
- Were self-hosted runners involved? GitHub warns that self-hosted runners can be persistently compromised by untrusted workflow code, which turns a GitHub incident into a host incident.
- Was code exfiltrated, altered or destroyed? These lead to different outcomes: notification review, integrity review of releases, or restore work.
- Did releases, packages or tags change? A tampered release moves the incident downstream to your customers (T1195.002).
- Is personal data in scope? Repositories holding customer data, test fixtures with real records, or credentials to production databases bring legal clocks into play.
Containment priorities
Work in this order. Speed beats completeness in the first pass; you can widen scope after the attacker is out.
- Secure the owners. Confirm every owner account is in the right hands, reset passwords, review registered two-factor methods and passkeys, and remove any owner you cannot vouch for. If a legitimate owner is locked out, use GitHub's documented 2FA account recovery, which involves verification and a support review that GitHub Docs puts at three or more business days, so do not depend on it during the incident; promote a trusted second owner instead.
- Suspend or remove the compromised members. Removing the account from the organisation cuts its access to private resources immediately, whatever credential it holds. With SAML single sign-on, also revoke the member's active SAML sessions from their linked identity page.
- Revoke tokens. Owners can view and bulk revoke fine-grained PATs from Settings, Active tokens, filtering by owner, repository or permission. Revocation removes organisation access but leaves SSH keys the token created working, and the token can still read public organisation resources. Classic PATs cannot be revoked by owners in that view: if your organisation still allows them, restrict classic PAT access by policy and revoke SAML authorisations, then require the user to delete the token. See How to revoke a leaked GitHub personal access token and check what it touched.
- Cut off apps. Remove unrecognised OAuth app access and uninstall unknown GitHub Apps. For a trusted app whose private key leaked, generate a new key and delete the old one. The GitHub Apps and OAuth apps audit how-to lists where each is visible.
- Freeze Actions. Temporarily disable Actions for affected repositories or the organisation, or limit allowed actions, so planted workflows cannot run while you clean up. Take self-hosted runners offline and treat them as compromised hosts.
- Remove deploy keys and SSH keys you do not recognise from affected repositories; use the unused deploy keys how-to to separate stale from malicious.
- Rotate secrets at the source. For every secret a malicious workflow could reference, rotate it with the issuing system (cloud provider, registry, package index, database), then update the GitHub secret. Changing only the GitHub value leaves the stolen copy valid. Cloud keys follow the Cloud Credential Compromise Playbook.
- Lock branches. Apply rulesets that block force pushes and direct pushes to default branches and require review, so the attacker cannot rewrite history while you investigate.
| Credential type | How to cut it off | What remains after |
|---|---|---|
| Member account | Remove from organisation; revoke SAML sessions | The personal account and its tokens still exist outside your org |
| Fine-grained PAT | Owner revokes in Active tokens or via the API (callable by GitHub Apps only) | SSH keys it created; read access to public resources |
| Classic PAT | Revoke SAML authorisation; policy restriction; user deletes token | Token valid elsewhere until deleted or expired |
| OAuth app token | Remove app access for the organisation; user revokes grant | Grant on the personal account until revoked |
| GitHub App | Uninstall, or rotate private key | Other installations of the same app |
| Deploy key or SSH key | Delete from repository or account | Copies of the private key held by the attacker, now useless |
| Actions secret | Rotate at issuing system, then update in GitHub | Any long-lived sessions the attacker opened with it, which need provider-side revocation |
Eradication
- Find every planted change: list commits to
.github/workflows, release tags and package manifests across all repositories in the incident window, grouped by author and token. Attackers commit under the victim's identity, so authorship alone proves nothing. - Revert, do not just delete: revert malicious commits through reviewed pull requests so history shows what changed. Where you must purge a secret from history, follow GitHub's sensitive data removal process and assume the secret was already copied.
- Check moved tags and releases: GitHub notes that a tag can be moved or deleted by anyone with access to the repository. Compare release tags with known-good commit SHAs and republish signed artefacts if any changed.
- Review persistence: webhooks pointing to unknown hosts, new outside collaborators, added owners, changed branch rules, new environments or environment secrets, and edited CODEOWNERS files.
- Rebuild self-hosted runners from clean images; do not clean them in place.
- Close the entry point: the phishing route, the leaked token location (public repository, image, log), or the infected developer workstation. An unrevoked credential was the reason GhostAction victims were hit again.
Recovery
- Restore deleted repositories. Owners can restore organisation repositories within 90 days of deletion; a repository can take up to an hour to become restorable. A repository in a non-empty fork network cannot be restored unless the rest of the network is deleted or detached, and team permissions are not restored, so reapply access from your records.
- Rebuild from clones where needed. Where restoration is blocked or history was overwritten, rebuild from developer clones or independent backups, then compare against the last trusted commit.
- Re-enable Actions in stages, with the
GITHUB_TOKENdefault set to read-only for contents, actions pinned to full-length commit SHAs, and.github/workflowscovered by CODEOWNERS so workflow changes need a designated reviewer. - Tighten access policy: require two-factor authentication or SSO, restrict or set a maximum lifetime for PATs, require approval for fine-grained PATs, and restrict OAuth app access to approved apps. The GitHub Organisation Security Checklist sets the baseline.
- Turn on secret scanning and push protection across the organisation so the next leaked credential is blocked or alerted on.
- Watch for return. Keep heightened alerting on the identities, IP ranges and workflow names involved for at least 30 days.
Evidence to preserve
The organisation audit log covers the last 180 days, and the web view shows three months by default, so export early. Exports are JSON or CSV, capped at 100 MB compressed or 10 minutes of processing. Git events (clones, fetches and pushes) do not appear in UI or API searches and must be exported. Stream the audit log to your SIEM if you have not already, because retention inside GitHub is finite (NIST SP 800-53 AU-11).
| Evidence | Why it matters | How to keep it |
|---|---|---|
| Audit log export for the incident window plus margin | Who did what, from where, with which token | Filtered JSON exports, hashed and stored read-only |
| Git events export | Proves or rules out code cloning | Separate export; not searchable in UI |
hashed_token search results for each known leaked token | Scope of a specific credential | Save query and output together |
| Malicious commits, workflow files and run logs | Shows what secrets were targeted | Archive before deleting; note logs may contain live secrets |
| App, token and key inventories before changes | Baseline of what existed | Screenshots or API output with timestamps |
| Self-hosted runner disk and memory | Host persistence and theft | Image before rebuild |
| Ransom notes and attacker contact details | Law enforcement and insurer | Copy before restoring repositories |
GitHub advises deleting any run log that exposed an unredacted secret and rotating that secret. Copy the log into your evidence store first, with restricted access.
Notification triggers
- Personal data: if repositories or stolen secrets exposed personal data, UK GDPR and EU GDPR Article 33 require notifying the supervisory authority within 72 hours of becoming aware, unless the breach is unlikely to result in a risk to individuals.
- Essential and important entities in the EU: NIS2 Article 23 requires an early warning to the CSIRT or competent authority within 24 hours of becoming aware of a significant incident, and an incident notification within 72 hours.
- US listed companies: SEC Form 8-K Item 1.05 requires disclosure within four business days of determining a cybersecurity incident is material.
- Customers and downstream users: if releases, packages or actions you publish were altered, tell consumers which versions to remove; contractual notice clauses often apply sooner than regulators.
- Credential issuers: tell cloud, registry and SaaS providers when their credentials were exposed so they can watch for misuse.
Lessons from incidents
- The Gitloker extortion campaign wiped and renamed repositories using stolen credentials and OAuth apps approved through phishing; an OAuth grant works as a standing credential that survives password changes.
- The GhostAction Returns 2026 wave pushed a fake security workflow to 772 repositories under victims' own identities; GitHub holding runs for approval limited confirmed theft, and accounts from earlier waves whose secrets had never been rotated were hit again.
- The Leaked GitHub App Private Keys 2026 case shows why a leaked app key must be rotated, not just removed from the file where it was found.
Framework mapping
| Playbook step | NIST SP 800-53 r5 | ATT&CK v20 technique addressed |
|---|---|---|
| Owner and member account control | AC-2 Account Management | T1078.004 Cloud Accounts, T1098 Account Manipulation |
| Token, app and key revocation | IA-5 Authenticator Management | T1528 Steal Application Access Token, T1098.001 Additional Cloud Credentials |
| Audit log review and export | AU-6, AU-11 | T1213.003 Code Repositories |
| Workflow and branch change control | CM-3 Configuration Change Control | T1195.002 Compromise Software Supply Chain |
| Restore and incident handling | IR-4 Incident Handling, IR-6 Incident Reporting | T1485 Data Destruction |
Practitioner checklist
- Keep at least two trusted organisation owners with phishing-resistant two-factor methods, and test that both can sign in.
- Stream the audit log to a SIEM and confirm git events are captured, before you need them.
- Record the SHA-256 hash of every leaked token and run a
hashed_tokensearch before revoking it. - Revoke at the right layer: remove members, revoke fine-grained PATs, remove apps and keys, then rotate secrets at their issuing system.
- Disable Actions or restrict allowed actions while planted workflows are found, and rebuild self-hosted runners from clean images.
- Restore deleted repositories inside the 90-day window and reapply team permissions from records.
- Require CODEOWNERS review for
.github/workflows, read-onlyGITHUB_TOKENdefaults and SHA-pinned actions. - Assess GDPR, NIS2 and SEC clocks as soon as personal data or material impact is possible.
Standards and references
- GitHub Docs: Reviewing the audit log for your organization
- GitHub Docs: Identifying audit log events performed by an access token
- GitHub Docs: Reviewing and revoking personal access tokens in your organization
- GitHub Docs: Viewing and managing a member's SAML access to your organization
- GitHub Docs: Security hardening for GitHub Actions
- GitHub Docs: Restoring a deleted repository
- NIST: SP 800-61 Rev. 3, Incident Response Recommendations and Considerations for Cybersecurity Risk Management
- EUR-Lex: Regulation (EU) 2016/679 (GDPR)
Related NHI Mgmt Group resources: GitHub and GitHub Actions Security Guide · GitHub Personal Access Tokens Security Guide · CI/CD Pipeline Compromise Playbook · Leaked Credential Response Playbook