A repository isn't just code: it may hold passwords someone committed by accident, depend on hundreds of third-party packages, and be pushed to by many people. Each of those is a way for things to go wrong. A leaked API key can be abused within minutes, an outdated package can contain a known vulnerability, and an unreviewed push to main can break production.
GitHub includes a set of security tools to guard against these risks, and many are switched on with a single click. Some prevent problems, such as branch protection and push protection; others detect them, such as Dependabot alerts and secret scanning.
In this lesson you'll protect your main branch, give collaborators the right level of access, keep dependencies up to date with Dependabot, stop secrets from being pushed, scan code for vulnerabilities, and learn the steps to take when something does leak. You'll find most of these settings in a repository's Settings and Security tabs.
Protecting main
Under Settings, Rules (rulesets) or Branches (classic branch protection), add a rule for main that can:
- Require a pull request before merging, with one or more approvals.
- Require status checks to pass, such as your Actions test workflow.
- Require conversation resolution, so review comments aren't ignored.
- Block force pushes and deletion of the branch.
- Require a linear history or signed commits if your team wants them.
Together these make the team workflow automatic: nobody can push broken or unreviewed code to main, even by accident.
People and permissions
Give each person the least access they need. Repositories owned by an organisation have five roles:
| Role | Can |
|---|---|
| Read | View and clone, open issues |
| Triage | Manage issues and pull requests, no code changes |
| Write | Push to branches and merge pull requests |
| Maintain | Manage the repository without access to sensitive settings |
| Admin | Everything, including settings and deletion |
On a personal repository, invited collaborators get write access. Review the list now and then under Settings, Collaborators, and remove people who no longer need access.
Dependabot
Modern projects depend on many packages, and vulnerabilities are found in them every week. Dependabot watches your dependency files, such as package.json or requirements.txt:
- Dependabot alerts tell you when a package you use has a known vulnerability, and how serious it is.
- Security updates open pull requests that upgrade the affected package to a fixed version.
- Version updates, configured with
.github/dependabot.yml, open regular pull requests to keep everything current.
Because they're ordinary pull requests, your tests run on them before you merge.
Secrets and code scanning
Secret scanning looks through your repository for tokens and keys from hundreds of services and alerts you, and many providers revoke leaked keys automatically. Push protection goes further: it blocks the push when it detects a secret, before it ever reaches GitHub.
Code scanning with CodeQL analyses your code for common vulnerability patterns, such as SQL injection or unsafe input handling, and shows results on pull requests. Finally, a SECURITY.md file tells people how to report a vulnerability privately instead of opening a public issue.
GitHub Security Syntax
Security files
.github/dependabot.yml # Dependabot version updates
.github/CODEOWNERS # required reviewers by path
.github/workflows/codeql.yml # code scanning
SECURITY.md # how to report vulnerabilities
.gitignore # keep .env and keys out of GitGitHub Security Summary
- Branch protection rules require pull requests, approvals and passing checks before merging into main.
- Give collaborators the least access they need: read, triage, write, maintain or admin.
- Dependabot alerts about vulnerable packages and opens pull requests to update them.
- Secret scanning finds leaked keys; push protection blocks them before they're pushed.
- A leaked secret must be revoked or rotated, because it remains in Git history.
GitHub Security Examples
Each example shows the code, the output it produces and what each part does.
Dependabot version updates
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"Every week Dependabot opens pull requests such as
"Bump express from 4.19.1 to 4.21.0", and every month
it updates the actions used in your workflows.Line-by-line explanation
- Lines 3 to 6Check npm packages listed in the root folder every week.
- Lines 7 to 10Keep the versions of actions in workflows current too.
Push protection stopping a secret
git commit -am "Add payment config"
git pushremote: error: GH013: Repository rule violations found for refs/heads/main.
remote: - GITHUB PUSH PROTECTION
remote: Push cannot contain secrets
remote: - GitHub Personal Access Token
remote: locations:
remote: - commit: 7b3e9d2
remote: path: config.js:3
To https://github.com/samlee/shop.git
! [remote rejected] main -> main (push declined due to repository rule violations)Line-by-line explanation
- Line 2The push is rejected before the token reaches GitHub. The output names the commit, file and line. To fix it, remove the token from the code, amend the commit (or rebase if it's older), load the value from an environment variable, and push again.
A security policy
# Security Policy
## Reporting a vulnerability
Please do not open a public issue.
Use the "Report a vulnerability" button on the Security tab,
or email security@example.com.
We aim to reply within 3 working days.
## Supported versions
| Version | Supported |
|---------|-----------|
| 2.x | Yes |
| 1.x | Security fixes only |GitHub links this file from the Security tab, so anyone
who finds a problem knows how to report it privately.Line-by-line explanation
- Lines 4 to 7A private reporting route, so attackers don't learn about the problem before it's fixed.
- Lines 9 to 13Which versions still receive fixes.
Common GitHub Security Mistakes
Deleting the file and moving on
git rm .env && git commit -m "Remove secrets" && git push# 1. revoke the key at the provider and create a new one
# 2. add .env to .gitignore
# 3. store the new key as an environment variable or Actions secretAdmin rights for everyone
All 12 collaborators: AdminDevelopers: Write Designers: Triage Two leads: AdminIgnoring Dependabot pull requests
37 open Dependabot PRs, the oldest from last yearReview and merge them weekly; tests on each PR show if anything breaksGitHub Security in Real Projects
Security in practice
Organisations commonly enforce branch protection and two-factor authentication across all their repositories, and security teams watch Dependabot and code scanning alerts from one dashboard. Public repositories get secret scanning and Dependabot at no extra cost, which is one reason open-source maintainers switch them on. Automated scanners also search all public GitHub code for leaked keys, which is why a key pushed by mistake can be abused within minutes.
GitHub Security FAQ
How do I report a security vulnerability in someone's project privately?
Look for a SECURITY.md file or the repository's Security tab, which explains how the maintainers want reports. Many repositories have private vulnerability reporting turned on, so you can submit a report that only maintainers see. Don't open a public issue for a security problem.
Is Dependabot free?
Yes. Dependabot alerts and Dependabot pull requests for security and version updates are free on GitHub.com, including for private repositories. You turn them on in the repository's security settings.
What is the difference between Dependabot alerts, security updates and version updates?
An alert tells you a dependency has a known vulnerability. A security update is a pull request Dependabot opens to upgrade that dependency to a fixed version. A version update is a regular pull request to keep dependencies current even when there's no vulnerability, configured in .github/dependabot.yml.
What does the Verified badge on a commit mean?
It means the commit was signed with a GPG, SSH or S/MIME key that GitHub could match to the author's account, so it really came from them. Commits made in GitHub's web editor are signed by GitHub automatically. Unsigned commits show no badge.
How do I remove a secret from my Git history?
Rotate or revoke the secret first, because removing it from history doesn't make it safe again. Then rewrite history with a tool such as git filter-repo, force-push, and ask collaborators to re-clone. Cached copies and forks may still contain the old commits.
GitHub Security Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Complete the name of the file that tells people how to report vulnerabilities.
.md
Which feature blocks a push that contains a secret?
What do branch protection rules let you require?
Which role can manage issues and pull requests but not push code?
An API key was pushed to a public repository an hour ago. What should you do first?
GitHub Security Quiz
5 questions to check what you learned.
What does Dependabot watch?
- Your commit messages
- Your project's dependencies, for vulnerabilities and new versions
- Your GitHub profile
- Other people's forks
What is the principle of least privilege?
- Everyone gets admin access
- Give each person only the access they need
- Nobody can push to main
- Only one person can use the repository
What does code scanning with CodeQL look for?
- Spelling mistakes in comments
- Large images
- Unused branches
- Common security vulnerability patterns in your code
Why doesn't deleting a committed secret in a new commit make it safe?
- The secret is still in the repository's history and may already have been copied
- Git refuses to delete files
- GitHub restores deleted files
- New commits are private
How do Dependabot pull requests stay safe to merge?
- They skip tests
- GitHub merges them automatically without checks
- They're ordinary pull requests, so your CI tests and reviews run on them before merging
- They only change the README