Skip to content

GH_PUSH_TO_DEFAULT

Copy page

Summary

Forestall ACL Alias GH_PUSH_TO_DEFAULT
Edge Type Attack Path
Affected Object Types GitHub Repositories
Exploitation Certainty Certain
GitHub Role / Permission Repository write (push) or maintain, on an unprotected default branch

Description

GH_PUSH_TO_DEFAULT represents that a user or team can push code directly to a repository’s default branch. The default branch is what CI/CD builds and deploys from, so the ability to write to it without review is a supply-chain foothold.

The edge is created only when both conditions hold:

  • The entity has write-level permission (push or maintain) on the repository, and
  • The default branch is not protected — there is no branch protection rule gating direct pushes. This is the relational form of the FS6021 (No Branch Protection) finding.

Admin holders are intentionally not given this edge: they are already modelled by GH_ADMIN (full control, which also includes the ability to remove protection and push). Archived repositories cannot be pushed to and are excluded.

When the default branch is protected (required reviews, status checks, or push restrictions), a direct push is blocked and this edge is not created — the writer must go through a reviewed pull request instead.

Identification

GitHub Web Interface

  1. Open the repository → Settings → Branches. If the default branch has no protection rule, direct pushes are allowed.
  2. Open Settings → Collaborators and teams. Any user or team with Write or Maintain can push directly to the unprotected default branch.

Exploitation

When the default branch is unprotected, a write-level entity can compromise the repository’s build and deployment pipeline with a single push:

  1. Inject a malicious GitHub Actions workflow. A workflow pushed to .github/workflows/ runs with the repository’s secrets and GITHUB_TOKEN. Where OIDC federation is configured, it can mint a cloud token and pivot out of GitHub entirely.

    # .github/workflows/ci.yml — attacker-controlled
    on: [push]
    permissions:
    id-token: write # request an OIDC token
    contents: read
    jobs:
    pivot:
    runs-on: ubuntu-latest
    steps:
    - uses: azure/login@v2 # exchange OIDC token for cloud creds
    with:
    client-id: ${{ secrets... }}
    tenant-id: ...
    subscription-id: ...
    - run: az account show # now operating in the cloud tenant
  2. Tamper with shipped code. Backdoor application source on the default branch so the next deploy carries the attacker’s payload to production.

  3. Exfiltrate secrets at build time. Print or transmit repository/environment secrets from a workflow step.

Because no review gates the push, the change reaches the default branch (and the pipeline) immediately — hence Certain certainty.

Mitigation

  1. Protect the default branch. Enable a branch protection rule (or a ruleset) on the default branch: require pull requests, require at least one review, and disallow direct pushes. This removes the edge entirely. See FS6021.

  2. Require review for workflow changes. Use CODEOWNERS to require an owner’s review for .github/workflows/ so workflow tampering cannot be self-merged.

  3. Grant least privilege. Prefer triage/read over write where contributors do not need to push. Manage write access through teams, not direct collaborator grants.

  4. Constrain Actions and OIDC. Set default workflow permissions to read-only, restrict which actions can run, and scope cloud federated-identity credentials (subject claim) to specific protected branches/environments rather than the whole repository.

  5. Include administrators in protection. Enable “Do not allow bypassing the above settings” so even admins cannot push directly to the default branch on sensitive repositories.

Detection

Monitor the GitHub audit log and Git events for direct writes to the default branch:

Event Description
git.push A push was received (correlate ref = default branch, no associated PR)
protected_branch.destroy A branch protection rule was removed (opens this edge)
repo.update_member / team.add_repository Write-level access was granted
workflows run from an unexpected actor A new/modified workflow executed shortly after a direct push

Alert on direct pushes to the default branch that are not associated with a reviewed pull request, on any removal of branch protection, and on workflow runs that request id-token: write from an unexpected actor.

References

Was this page helpful?

Thank you for your feedback.