GitHub provides a comprehensive set of security features, but most of them are not enabled by default. A repository with default settings has no branch protection, no required reviews, no secret scanning, and no automated dependency updates. This guide walks through every security setting you should configure.
Branch Protection Rules
Branch protection is the foundation of repository security. Configure it for your main branch:
Settings > Branches > Branch protection rules > Add rule
Pattern: main (or master)
Required Settings
- Require a pull request before merging. No direct pushes to main.
- Require approvals. At least one approval from a code owner or team member.
- Dismiss stale pull request approvals when new commits are pushed. If the author pushes new code after approval, the approval resets.
- Require review from Code Owners. If you have a CODEOWNERS file, require their approval.
- Require status checks to pass before merging. Select your CI checks, linting, and security scans.
- Require branches to be up to date before merging. Prevents merge skew.
- Require signed commits. Ensures commit authorship is verified with GPG or SSH keys.
- Do not allow bypassing the above settings. Even administrators should follow the rules.
# .github/CODEOWNERS
* @your-org/engineering-leads
/security/ @your-org/security-team
*.lock @your-org/security-team
Additional Branch Protection
- Restrict who can push to matching branches. Limit to deployment bots and team leads.
- Allow force pushes: Never. Force pushes rewrite history and can destroy audit trails.
- Allow deletions: Never. Protected branches should not be deletable.
Secret Scanning
GitHub scans your repository for accidentally committed secrets like API keys, tokens, and credentials.
Settings > Code security and analysis > Secret scanning: Enable
Also enable:
- Push protection. Blocks pushes that contain detected secrets before they reach the repository. This is the most valuable feature since it prevents secrets from entering your Git history.
- Secret scanning alerts. Get notified when a secret is detected in existing code.
GitHub detects patterns from dozens of providers: AWS, Azure, GCP, Stripe, Twilio, Slack, and many more.
Custom Secret Patterns
Define custom patterns for your organization's secret formats:
Settings > Code security and analysis > Secret scanning > Custom patterns
# Example: internal API key format
yourcompany_api_[a-zA-Z0-9]{32}
Dependabot
Dependabot Alerts
Enable automatic alerts for vulnerable dependencies:
Settings > Code security and analysis > Dependabot alerts: Enable
GitHub checks your dependency manifests (package.json, requirements.txt, pom.xml, etc.) against the GitHub Advisory Database and notifies you of known vulnerabilities.
Dependabot Security Updates
Enable automatic PRs for security fixes:
Settings > Code security and analysis > Dependabot security updates: Enable
When a vulnerability is found, Dependabot creates a PR that bumps the dependency to the patched version. These PRs should be prioritized and merged quickly.
Dependabot Version Updates
Configure regular dependency updates in .github/dependabot.yml:
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
reviewers:
- "your-org/security-team"
labels:
- "dependencies"
groups:
minor-and-patch:
update-types:
- "minor"
- "patch"
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
Pin GitHub Actions to specific commit SHAs, not tags:
# Good: pinned to SHA
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
# Risky: tag can be moved
- uses: actions/checkout@v4
Code Scanning (CodeQL)
Enable GitHub's CodeQL analysis for automated security scanning:
Settings > Code security and analysis > Code scanning: Set up
Or add a workflow file:
# .github/workflows/codeql.yml
name: "CodeQL"
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 6 * * 1'
jobs:
analyze:
runs-on: ubuntu-latest
permissions:
security-events: write
strategy:
matrix:
language: ['javascript', 'python']
steps:
- uses: actions/checkout@v4
- uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
- uses: github/codeql-action/autobuild@v3
- uses: github/codeql-action/analyze@v3
CodeQL finds SQL injection, XSS, path traversal, and dozens of other vulnerability patterns.
Repository Access
Collaborator Permissions
Follow the principle of least privilege:
- Read: For most team members who need visibility.
- Write: For active contributors.
- Maintain: For tech leads.
- Admin: For repository owners only.
Deploy Keys
Use deploy keys instead of personal access tokens for CI/CD:
Settings > Deploy keys
Deploy keys are scoped to a single repository. Personal access tokens can access all repositories the user has access to.
GitHub Apps
Prefer GitHub Apps over OAuth apps for integrations. GitHub Apps have fine-grained permissions and are installed on specific repositories.
Security Policy
Add a SECURITY.md file to tell researchers how to report vulnerabilities:
# Security Policy
## Reporting a Vulnerability
Email security@yourcompany.com with details.
Do not open a public issue for security vulnerabilities.
We will acknowledge your report within 48 hours.
How Safeguard.sh Helps
Safeguard.sh complements GitHub's built-in security features by providing cross-repository visibility. While GitHub's Dependabot and code scanning work on individual repositories, Safeguard.sh aggregates findings across your entire organization. It shows you which repositories have the most critical unpatched vulnerabilities, tracks remediation progress, and provides a unified dashboard for your security posture across all your GitHub repositories. When you need to answer "are we affected by CVE-2024-XXXXX?" across hundreds of repos, Safeguard.sh gives you the answer in seconds.