Skip to main content
Back to blog
April 28, 2026|8 min read|Antoine Duno

GitHub Repository Security: Complete Guide for 2026

Your GitHub repository is the source of truth for your entire application — and a prime target for supply-chain attacks. Here's how to protect it at every layer.

ZeriFlow Team

1,498 words

GitHub Repository Security: Complete Guide for 2026

GitHub security is not just about protecting source code — it's about securing the entire software supply chain. A compromised repository can poison your deployments, expose secrets, and provide attackers with a foothold into your production environment. The controls available in GitHub's security features, when properly configured, create a layered defense that significantly raises the cost of an attack.

Check your site's security right now: Free ZeriFlow scan →

1. Secret Scanning: Your First Line of Defense

GitHub's Secret Scanning automatically scans push events and commit history for known credential patterns — AWS access keys, GitHub tokens, Stripe keys, database URLs, and hundreds of other credential types.

Enable it now (if you haven't already):

For public repositories: secret scanning is on by default and cannot be disabled. For private repositories on GitHub Advanced Security (included in GitHub Enterprise and GitHub Teams): navigate to Settings → Code security → Secret scanning → Enable.

Push protection: Enable "Push protection" to block commits containing secrets at push time, before they ever enter the repository. This is more valuable than scanning after the fact — once a secret is committed, you must assume it's been exfiltrated.

What to do when a secret is detected:

  1. 1Rotate the secret immediately — treat it as compromised regardless of repository visibility.
  2. 2Revoke the exposed credential in the issuing service.
  3. 3Review access logs for the compromised credential to assess what was accessed.
  4. 4Clean the secret from git history using git filter-repo (not git filter-branch, which is deprecated).

Pre-commit hooks: Add a pre-commit hook locally using detect-secrets or gitleaks to catch secrets before they reach GitHub at all.


2. Branch Protection Rules

Branch protection prevents force-pushes, deletions, and direct commits to your most important branches. For most teams, main and any release branches need robust protection.

Configure via Settings → Branches → Add branch protection rule:

  • Require pull request reviews before merging — minimum 1-2 reviewers, depending on team size.
  • Dismiss stale pull request approvals when new commits are pushed — prevents the scenario where an approval is given, then the code is changed before merge.
  • Require status checks to pass before merging — block merges if CI tests fail or security scans report issues.
  • Require conversation resolution before merging — ensures review comments are addressed.
  • Require signed commits — see section 5.
  • Include administrators — don't exempt admins from these rules; insider threats and compromised admin accounts are real.
  • Do not allow bypassing the above settings — explicitly locks out force-merges.

For organizations, use Rulesets (the newer system) rather than branch protection rules — they're more flexible and apply across multiple branches with regex patterns.


3. Dependabot: Automated Dependency Security

Outdated dependencies with known CVEs are one of the most common attack vectors. Dependabot automates the detection and remediation of vulnerable dependencies.

Enable in Settings → Code security:

  • Dependabot alerts — notifies you when a dependency has a known vulnerability.
  • Dependabot security updates — automatically opens PRs to update vulnerable dependencies to patched versions.
  • Dependabot version updates — optionally, keep all dependencies up to date (not just security-relevant ones).

Configure dependabot.yml in .github/ for fine-grained control:

yaml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 10
    labels:
      - "dependencies"
      - "security"

Run a free ZeriFlow scan → on the deployed application from your repo to verify that dependency updates have resulted in improved security header and TLS configuration.

Review Dependabot PRs carefully. Automated dependency updates can introduce breaking changes. Your CI pipeline (test suite + build) is the safeguard — ensure it runs on all Dependabot PRs before auto-merge is triggered.


4. Code Scanning with CodeQL

GitHub's Code Scanning with CodeQL performs static analysis of your source code to identify security vulnerabilities — SQL injection, XSS, path traversal, insecure deserialization, and more — before they reach production.

Enable via Security → Code scanning → Set up CodeQL analysis.

This creates a GitHub Actions workflow in .github/workflows/codeql.yml:

yaml
- uses: github/codeql-action/analyze@v3
  with:
    languages: javascript, typescript  # or python, java, go, etc.
    queries: security-and-quality

Best practices:

  • Run CodeQL on every pull request (already the default when enabled via UI).
  • Block merges when CodeQL finds high-severity issues (configure this in branch protection status checks).
  • Address CodeQL findings promptly — the "dismiss" option should be used only with documented justification.
  • Enable the security-extended query suite for a more comprehensive scan (at the cost of more noise).

Third-party scanning: CodeQL is GitHub-native, but also consider integrating Snyk, Semgrep, or SonarCloud for additional coverage.


5. Signed Commits and CODEOWNERS

Signed commits provide cryptographic proof that a commit was authored by a specific identity — preventing commit spoofing (where an attacker creates commits appearing to come from a trusted developer).

Enable Vigilant Mode on your GitHub account (Settings → SSH and GPG keys → Vigilant mode) to mark unsigned commits with a "Unverified" badge. Require signed commits in your branch protection rules.

To sign commits locally:

bash
# Generate a GPG key
gpg --gen-key

# Configure git to use it
git config --global user.signingkey YOUR_KEY_ID
git config --global commit.gpgsign true

Or use SSH signing (simpler, supported since Git 2.34):

bash
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub

CODEOWNERS enforces review requirements on specific files or directories:

# .github/CODEOWNERS
# Security-sensitive files require review from the security team
/.github/workflows/    @org/security-team
/infrastructure/       @org/devops-team
/src/auth/             @org/security-team

When a PR modifies a CODEOWNERS file, the listed owners are automatically added as required reviewers. This ensures your CI/CD configurations and authentication code always receive expert review.


6. GitHub Actions Security

GitHub Actions is a powerful CI/CD system — and also an increasingly targeted attack surface. Malicious Actions, compromised dependencies, and overly-permissive workflow permissions can be used to exfiltrate secrets or push malicious code.

Permission scoping:

yaml
# Minimum permissions per workflow
permissions:
  contents: read
  pull-requests: write  # Only if the workflow needs to comment on PRs

Add permissions: read-all at the top of the workflow file and override specific permissions as needed. This is safer than the default (which grants write access to several APIs).

Pin Actions to specific commit SHAs:

yaml
# Insecure: can be changed by the action author
- uses: actions/checkout@v4

# Secure: pinned to a specific immutable commit
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683

Pinning to SHAs prevents a supply-chain attack where a trusted Action's tag is moved to malicious code.

Secrets handling:

  • Never print secrets to workflow logs (echo $SECRET will be masked, but echo ${SECRET:0:4} will not be caught by masking).
  • Use ${{ secrets.SECRET_NAME }} syntax — never interpolate secrets directly into shell commands where possible.
  • Use environment secrets rather than repository secrets for secrets that should only be accessible in specific deployment contexts (e.g., production vs staging).

FAQ

### Q: How do I remove a secret that was accidentally committed to a public GitHub repo? A: Rotate the secret immediately — assume it's compromised. Then use git filter-repo to remove it from history and force-push the cleaned branch. Contact GitHub Support if the commit is visible in forks. Enable secret scanning and push protection to prevent recurrence.

### Q: Is GitHub Secret Scanning available for free accounts? A: Secret scanning with push protection is available on all public repositories for free. For private repositories, it requires GitHub Advanced Security (included in GitHub Enterprise Cloud and GitHub Teams plans).

### Q: What's the difference between Dependabot security updates and version updates? A: Security updates only open PRs for dependencies with known CVEs in the GitHub Advisory Database — targeted and lower noise. Version updates keep all dependencies current, which is broader in scope and generates more PRs. Enable both, but review version update PRs more carefully.

### Q: How do I enforce that all contributors sign their commits? A: Enable "Require signed commits" in branch protection rules (or Rulesets). This blocks merges of unsigned commits to protected branches. Note: merge commits created by GitHub's web interface (squash/rebase merge) are signed by GitHub regardless of the original commit signatures.

### Q: Should I use GitHub Actions OIDC instead of storing cloud credentials as secrets? A: Yes, strongly preferred. OIDC (OpenID Connect) lets your GitHub Actions workflows request short-lived credentials from AWS, GCP, or Azure without storing long-lived keys as secrets. This eliminates the most common secret-exposure vector in CI/CD pipelines.


Conclusion

GitHub repository security is a combination of access controls (branch protection, CODEOWNERS, 2FA), automated detection (secret scanning, Dependabot, CodeQL), and CI/CD hardening (Actions permissions, pinned dependencies). The goal is defense in depth: multiple independent layers, each raising the cost of a successful attack.

Your repository's security also extends to the deployed application it produces. After hardening your repository, validate the external security posture of what gets deployed.

Run a free ZeriFlow scan → — 60 seconds, no credit card.

Ready to check your site?

Run a free security scan in 30 seconds.

Related articles

Keep reading