How to Enable GitHub Secret Scanning and Push Protection (2026)

How-To Guide

Push protection blocks a commit containing an API key. Then the developer picks "it's a false positive" from a dropdown, and the push goes through. GitHub records an alert that is already marked closed, so nobody is notified and nothing lands in anyone's queue.

That's the default behaviour on a repository with push protection enabled, and it's the part most teams don't find out about until they audit their alert history. GitHub's own docs lay it out in a table, which we'll get to.

TL;DR

Secret scanning is free and automatic on public repos. Private repos need GitHub Secret Protection, a paid add-on on Team or Enterprise Cloud. Turn on push protection too, then immediately configure delegated bypass, because by default anyone with write access can wave a blocked push through and two of the three bypass reasons close the alert on the spot. GitHub will not block passwords or older token formats at all.

What your plan actually includes

This trips people up because the answer changed when GitHub unbundled the feature from Advanced Security into a standalone product called GitHub Secret Protection.

Repository typeSecret scanningCost
PublicRuns automaticallyFree
Organization-owned private or internalNeeds GitHub Secret ProtectionPaid, on Team or Enterprise Cloud
User-owned privateNeeds Enterprise Cloud with Enterprise Managed UsersPaid

GitHub's wording is unambiguous for the free case: on public repositories, "secret scanning runs automatically for free." You don't enable anything. If your repo is public, it is already being scanned, and any alerts are already sitting in the Security tab.

If your repo is public and you have never looked at Security, then Secret scanning alerts, go look now. Scanning has been running the whole time. The alerts exist whether or not anyone has read them.

Enable secret scanning on a private repo

1

Open the repository's security settings

Go to the repository, then Settings, then Advanced Security in the sidebar.

2

Turn on secret scanning

Find Secret scanning and click Enable. On an org-owned private repo this requires GitHub Secret Protection on the org's plan. If the button is greyed out, that's the reason, and it's an org-level purchase rather than something you can fix in the repo.

Scanning starts with a full history pass, so alerts for old commits appear within minutes rather than waiting for your next push.

Enable push protection

Scanning tells you about a secret after it's in the repo. Push protection is the part that tries to stop it getting there.

3

Turn it on

In the same Advanced Security settings panel, enable Push protection. GitHub now inspects each push and rejects any that contains a detected secret, printing the secret type, the file, and the commit SHA in the git output.

For pushes to public repositories from a personal account, push protection for users is already enabled by default on GitHub.com. You get it without asking.

Push protection is a speed bump, not a wall

Here's the part worth internalising. When GitHub blocks a push, the developer isn't stuck. By default anyone with write access can bypass the block by choosing a reason, and the reason they pick decides whether anyone ever hears about it:

Bypass reasonWhat GitHub does
It's used in testsCreates a closed alert, resolved as "used in tests"
It's a false positiveCreates a closed alert, resolved as "false positive"
I'll fix it laterCreates an open alert

Two of the three options file the alert as already resolved. A developer under deadline pressure who genuinely believes the string is a test fixture will pick the first option honestly, and if they're wrong, a live credential is now in your history with a closed alert attached to it.

A closed alert does not mean the secret was fake. It means someone clicked a dropdown. When you audit a repo, read the closed alerts resolved as "used in tests" and "false positive" as well as the open ones. In scans we regularly find live keys sitting behind a resolution someone chose in good faith.

The fix GitHub ships for this is delegated bypass. With it configured, bypass stops being self-service: you grant bypass privileges to specific people, and everyone else's blocked push becomes a request that one of those people reviews and approves. If you're turning push protection on for a team rather than a solo project, turn this on in the same sitting. Otherwise the control is advisory.

Four things it will not catch

GitHub's coverage is genuinely good on service tokens with recognisable shapes. These are the documented gaps, straight from GitHub's pattern reference:

Passwords. "Push protection and validity checks are not supported for passwords." A database password or a full connection string in a committed config file is exactly this case, and it's a common one in vibe-coded projects where the database URL got pasted somewhere during setup.

Older token formats. "Push protection only supports the most recent token versions that secret scanning can identify with confidence." GitHub made that choice deliberately to avoid false-positive blocks, which is reasonable, but it means a key issued under a provider's previous format can be pushed without resistance.

Validity checks on generic secrets. GitHub can tell you whether a detected Stripe or AWS key is still live by asking the provider. That only works for recognised partner patterns. For anything generic, "validity checks are not supported," so you get an alert with no signal about whether the credential still works.

Anything that never reaches GitHub. This is the big one and it isn't a limitation so much as a boundary. Secret scanning reads your repository. A key in a gitignored .env, a key pasted into a Vercel or Railway dashboard, a key bundled into your client-side JavaScript at build time: none of those are in git, so none of them are scanned. The credential is still exposed, just not where GitHub is looking.

Worth knowing how the generic detection works, because it's newer than most guides assume: GitHub "uses Copilot to detect generic secrets using AI" rather than pure regex. That's why you'll see alerts on high-entropy strings that don't match any known provider format, and why those alerts can't be validity-checked.

Scanning history with your own tools

Everything above is GitHub's native feature. If what you actually need is to sweep a repo's full history yourself, with gitleaks or detect-secrets, run it locally, and wire it into a pre-commit hook and CI, that's a different job and it has its own guide:

Detect Secrets in Git: Tools and Patterns covers gitleaks git --source . for the history sweep, the pre-commit setup, the .gitleaksignore workflow for false positives, and the GitHub Actions step (including the fetch-depth: 0 that everyone forgets).

The two approaches stack well. GitHub's scanning is always-on and needs no maintenance. A local gitleaks run covers the repos and files GitHub can't see, catches the older token formats push protection waves through, and works before anything is pushed anywhere.

If you only do one thing after reading this: open Security, then Secret scanning alerts, and filter to closed alerts. That list is where the interesting findings usually are.

You found a secret. Now what?

Order matters here, and most people get it backwards by cleaning history first.

  1. Rotate the credential in the provider's dashboard. Until you do, nothing else you do matters, because the key is already out.
  2. Check the provider's access logs for use you don't recognise.
  3. Clean history with BFG or git filter-repo, but only if the repo is or ever was public. On a private repo with a rotated key this is often not worth the force-push disruption.
  4. Close the alert with an accurate resolution, so the next person auditing the repo gets a true picture.

Is GitHub secret scanning free?

On public repositories, yes. GitHub's docs say secret scanning "runs automatically for free" there, and push protection for users is on by default. Private and internal repositories are different: they need GitHub Secret Protection, which is a paid add-on on GitHub Team or GitHub Enterprise Cloud.

Can someone bypass push protection?

Yes. By default anyone with write access can bypass a block by picking one of three reasons. Two of them ("it's used in tests" and "it's a false positive") create an alert that is already closed, so nobody gets a notification to follow up. Only "I'll fix it later" leaves an open alert. Configure delegated bypass if you want a blocked push to become a review request instead.

Does GitHub secret scanning find secrets already in my git history?

Yes, scanning covers the full history of the repository, not just new commits. Push protection is the part that only applies going forward, because it inspects the push. If scanning surfaces an old secret, rotate it first. It has been readable by anyone who cloned the repo for as long as it has been there.

Will secret scanning catch a password?

Not reliably, and it will never block one. GitHub's pattern reference states plainly that "push protection and validity checks are not supported for passwords." Database passwords and connection strings in a committed config file are exactly the case this misses.

Do I still need gitleaks if GitHub secret scanning is on?

Usually yes, for two reasons. GitHub only sees code you push to GitHub, so a secret in an untracked .env or pasted into a hosting dashboard is invisible to it. And push protection only blocks the most recent token formats, so an older-style key can sail through. A local gitleaks run covers both cases.

The keys GitHub can't see

Secret scanning reads your repository. It never sees the API key your build inlined into client-side JavaScript, or the one sitting in a hosting dashboard. CheckYourVibe scans your live app for exactly those, plus exposed endpoints and misconfigured headers.

How-To Guides

How to Enable GitHub Secret Scanning and Push Protection (2026)