Missing Branch Protection Rules
Without branch protection on main/production branches, any developer (or compromised account) can push directly, force-push destructive changes, or merge without code review, bypassing all quality and security gates.
How It Works
Branch protection rules are GitHub's mechanism for enforcing review and CI requirements before code reaches important branches. Without them, there is nothing preventing a developer from pushing directly to main, force-pushing to rewrite history, merging a PR without review, or bypassing failing CI checks. If a developer's account is compromised via credential theft or social engineering, the attacker has unrestricted access to modify production code. Even without malicious intent, lack of branch protection means accidental force-pushes, untested code, and unreviewed changes can reach production. This is especially dangerous when CI/CD automatically deploys from main.
# BAD: no branch protection configured (shown as Terraform for GitHub)
resource "github_repository" "app" {
name = "production-app"
visibility = "private"
# No branch protection resource defined
# Anyone can push directly to main
# No required reviews, no status checks
# Force push is allowed
}
# Result: developers push directly to main
# git push origin main -- works without review
# git push --force origin main -- rewrites history# GOOD: branch protection with required reviews and status checks
resource "github_branch_protection" "main" {
repository_id = github_repository.app.node_id
pattern = "main"
enforce_admins = true
required_pull_request_reviews {
required_approving_review_count = 1
dismiss_stale_reviews = true
require_code_owner_reviews = true
}
required_status_checks {
strict = true # branch must be up-to-date before merging
contexts = ["ci/test", "ci/lint", "security/scan"]
}
restrict_pushes {
blocks_creations = true
}
allows_force_pushes = false
allows_deletions = false
}Real-World Example
In the 2020 PHP Git server compromise, attackers pushed malicious commits directly to the php-src repository's main branch, adding a backdoor to the PHP source code. The commits were disguised as typo fixes. This incident led PHP to migrate to GitHub and implement branch protection rules requiring PR reviews. It demonstrated how a single unprotected branch can allow supply chain attacks affecting millions of downstream users.
How to Prevent It
- Enable branch protection on all main/production branches requiring at least one pull request review before merging
- Require status checks to pass (CI tests, linting, security scans) before allowing merges
- Disable force pushes and branch deletions on protected branches to prevent history rewriting
- Enable 'enforce admins' so that even repository administrators must follow the protection rules
Affected Technologies
Data Hogo detects this vulnerability automatically.
Scan Your Repo FreeRelated Vulnerabilities
Unpinned GitHub Actions
highUsing GitHub Actions referenced by mutable tags like @main or @v3 instead of full commit SHAs means a compromised or hijacked action can inject malicious code into your CI pipeline without any change to your workflow file.
GitHub Actions Script Injection
criticalUsing untrusted event data like github.event.issue.title directly inside run: blocks allows attackers to inject arbitrary shell commands into your CI pipeline by crafting malicious issue titles, PR bodies, or commit messages.
Secrets Leaked in CI Logs
highPrinting or echoing environment variables containing secrets in CI scripts exposes them in build logs, which are often accessible to all repository collaborators and sometimes publicly visible on open-source projects.
Self-Hosted Runner Risks
highUsing self-hosted GitHub Actions runners with pull_request_target or public fork workflows allows untrusted code from external contributors to execute on your infrastructure with access to secrets, persisted state, and the host network.