Secret scanning reads your repository’s content — all of it, including history — looking for strings that match known credential formats. When it finds one, it raises an alert and, for many providers, tells the provider directly.
It is a detection control. By the time it fires, the credential is already in the repository, in every clone of it, and — on a public repository — potentially already in use by somebody else.
That framing matters, because secret scanning is frequently described as though it prevented leaks. It does not. Push protection is the feature that tries to do that, and the two are separate for a reason.
The short answer
Section titled “The short answer”What it does. Scans repository content against a large set of credential patterns, plus generic patterns and AI-based detection, and raises alerts for matches.
Where it looks. The entire Git history across all branches, issue titles, descriptions and comments, pull request titles, descriptions and comments, Discussions, wikis, and secret gists.
What happens on a match. An alert appears in the repository’s security tab. For a partner pattern — a format a participating provider registered — GitHub also notifies the provider, who typically revokes or flags the credential themselves.
Availability. Free and enabled by default on public repositories. On private and internal repositories it requires GitHub Secret Protection, purchasable on GitHub Team and GitHub Enterprise plans.
What it does not do. Stop the secret arriving, revoke the credential for you (outside the partner programme), find credential formats it does not model, or remove anything from history.
Why detection is not enough, stated plainly
Section titled “Why detection is not enough, stated plainly”A secret scanning alert tells you a credential has been in your repository, is in every clone anyone has made, and — if the repository is public — has been available to anyone watching the public event stream.
Public repositories are scraped continuously by automation whose entire purpose is finding credentials. The interval between a push and the first use of a leaked cloud key is commonly measured in minutes, and the scraping does not wait for GitHub to raise an alert.
So an alert is the beginning of an incident, not the end of a problem:
- Rotate or revoke the credential. First. Before anything else.
- Determine exposure — what it could reach, and whether it was used.
- Remove it from current files so it stops being re-committed.
- Decide whether history needs rewriting, which is optional and disruptive.
- Close the alert with an accurate reason.
Steps 1 and 2 are rotating exposed credentials. Steps 3 and 4 are removing secrets from history. This page is about how you found out.
The surfaces that get scanned
Section titled “The surfaces that get scanned”Wider than most people assume, and the non-code surfaces are where teams are most often surprised.
| Surface | Notes |
|---|---|
| Git history, all branches | Not just the default branch, and not just the current tree |
| Issues | Titles, descriptions and comments, including historical ones |
| Pull requests | Titles, descriptions and comments |
| Discussions | Body and comments |
| Wikis | Content pages |
| Secret gists | “Secret” gists are unlisted, not private |
Two of these matter more than they look.
Issues and pull request comments. “Here is the error I am getting” pasted with a stack trace, a
curl command or a config dump is one of the most common ways a credential enters a repository, and
it never touches the code at all.
Secret gists. They are not access-controlled — anyone with the URL can read one. A credential in a “secret” gist is published to anyone who obtains the link, and links leak.
Pattern types
Section titled “Pattern types”Detection is not one mechanism. Four kinds of pattern operate with different confidence and different consequences.
Partner patterns
Section titled “Partner patterns”Formats registered by participating providers — cloud platforms, payment processors, SaaS vendors.
The distinctive property: when GitHub matches a partner pattern in a public repository, it notifies the provider. The provider then acts on their own terms, which usually means revoking the credential, quarantining it, or contacting the account owner directly.
This is genuinely the fastest remediation available, because it does not depend on you noticing. It also means partner secrets are handled outside your alert list — GitHub does not display those matches as repository alerts, because the response is happening at the provider.
The practical consequence: an email from a cloud provider saying your key was disabled is a secret scanning outcome, and it is frequently the first thing anybody notices.
Generic patterns
Section titled “Generic patterns”Credentials not tied to a specific provider — private keys, connection strings, generic API keys.
Higher recall, lower precision. A connection string in a test fixture and a connection string in production configuration look identical to a pattern matcher, so this is where false positives live. That is a reasonable trade: a missed private key is worse than a reviewed false positive.
AI-detected secrets
Section titled “AI-detected secrets”Detection of unstructured credentials — passwords and similar strings that have no fixed format — and the generation of regular expressions for custom patterns.
This is the category that closes the largest historical gap. A hardcoded password has no prefix, no length convention and no distinguishing shape, so no regular expression finds it reliably. It is also inherently probabilistic: expect it to be the noisiest source and to need the most tuning.
Custom patterns
Section titled “Custom patterns”Your own formats. If your organisation issues internal service tokens, nothing GitHub ships will match them.
Writing a custom pattern is the single highest-value action available to an organisation with in-house credential formats, because it converts an entire class of credential from invisible to detected. Two things make it work:
- A distinctive prefix on the credential itself. If you also issue the tokens, give them one. A token that looks like any other 32-character string is one nothing can find.
- A dry run before enabling. Custom patterns can be evaluated against existing content first, which tells you the false positive rate before it becomes everyone’s problem.
Validity checks
Section titled “Validity checks”For supported providers, GitHub can check whether a detected credential is still active and display that on the alert.
This is the most useful triage input available, because it splits the queue in the only way that matters operationally:
- Active — a working credential is in your repository. This is an incident, now.
- Inactive — already revoked or expired. Still worth cleaning up, not an emergency.
- Unknown — validity could not be determined. Treat as active.
Without validity, every alert looks the same, and a repository with two hundred historical alerts — mostly long-dead test credentials — produces exactly the fatigue that causes a real one to be missed.
Working an alert
Section titled “Working an alert”An alert has three pieces of information: what was found, where, and — where available — whether it still works.
-
Read the validity first. Active moves everything else down the queue.
-
Identify the credential. Not the pattern name — the actual thing. Which system, which account, what it can do. An alert that says “AWS access key” does not tell you whether it is a read-only key for a sandbox or an administrator key for production.
-
Rotate it. Even if it looks like a test credential, even if it looks expired, unless you can establish otherwise. This step takes minutes and the alternative is a judgement call under uncertainty.
-
Find every place it is used, so rotation does not break something at an inconvenient moment.
-
Remove it from the current files. Replace it with a reference to a secret manager, an environment variable, or an Actions secret.
-
Decide about history. Rewriting is disruptive and usually unnecessary once the credential is dead. It becomes worth doing when the value is intrinsically sensitive — a private key, a customer’s data — rather than merely a revocable token.
-
Close the alert with an accurate reason. The reason is the only record of the judgement.
Closing alerts honestly
Section titled “Closing alerts honestly”The dismissal reasons offered are, in effect, claims you are making. Each has a correct use:
Revoked — you rotated it. The strongest and most common resolution.
False positive — it is not a credential at all. An example string, a hash, a UUID that matched a pattern. Verify before choosing this; “it looks like an example” is not the same as “it is one”.
Used in tests — it is real, and it authenticates to something whose compromise you have decided is acceptable. Be honest about whether that is true. Test credentials that reach shared infrastructure are production credentials with a misleading name.
Won’t fix — you have decided to accept it. This requires a reason somebody can read later, and it is the dismissal most likely to be regretted.
The threat model
Section titled “The threat model”Threat. A working credential exists in repository content, and somebody other than its owner uses it.
Attack surface. Everything on the scanned-surfaces list, plus everything the scanner cannot see: forks, clones on laptops and CI runners, mirrors, backups, and any copy taken while the content was accessible. Note that scanning covers your repository — it has no reach into any of those copies.
Impact. Determined by the credential, not by the repository. A read-only API key for a public dataset in a public repository is nearly nothing. A cloud administrator key in a private repository with forty collaborators is a full compromise, and the private setting bought you very little.
Control. Detection is this feature. The controls that actually reduce the threat are prevention (push protection, pre-commit scanning, secrets living in a manager), and short credential lifetimes, so an undetected leak stops working on its own.
Verification. Push a deliberately fake but correctly shaped credential to a disposable public repository and confirm the alert appears, how long it takes, and what it says. Do the same with your organisation’s own token format — if nothing fires, you have found the case for a custom pattern.
The verification worth repeating annually is the last one. Credential formats change, teams introduce new services, and the set of things your detection actually covers drifts away from the set of things you issue.
Timing, and what “detected” means operationally
Section titled “Timing, and what “detected” means operationally”Detection is not instantaneous, and the gap has practical consequences.
Scanning runs when content is pushed, and also historically when a feature is newly enabled — which is why turning it on for the first time across an established organisation produces a large initial wave of alerts covering years of history. That wave is the single most common reason secret scanning gets ignored: several hundred findings arrive at once, most of them long-dead, and nobody has a way to tell which two matter.
The way through it:
Filter by validity first. Active credentials are the queue. Everything else is a backlog.
Then filter by provider. Cloud and payment credentials outrank an expired analytics key.
Then treat the rest as a project, not a queue. A security campaign with an owner and a deadline is the mechanism designed for exactly this shape of work.
The related timing point: for a public repository, external scrapers do not wait for your alert. Their detection is concurrent with GitHub’s, and their action on a finding is faster than yours. Plan on the assumption that a credential pushed to a public repository is compromised at the moment of the push, not at the moment of the alert.
Where secret scanning stops
Section titled “Where secret scanning stops”Knowing the boundary is what separates defence in depth from believing you are covered.
It matches patterns. A credential with no recognisable shape — a bespoke internal token, a password, a base64 blob — is found only by the AI detection or a custom pattern you wrote.
It does not know what a credential can do. Every alert looks equally severe. The one for a read-only sandbox key and the one for a production administrator key are the same alert, and only you can tell them apart.
It does not rotate anything. Except through the partner programme, where the provider acts. Your alert being closed does not mean the credential is dead.
It does not clean history. Alerts point at content; removing it is a separate, deliberate operation.
It is retrospective by definition. The secret was pushed. Prevention is push protection.
It does not cover everything, everywhere. Encoded, compressed or encrypted content, binary artefacts, and anything outside the scanned surfaces are invisible to it.
What this means for your stack
Section titled “What this means for your stack”Secret scanning is one layer, and the layers around it exist because of the list above.
- Push protection in front of it, so supported patterns never land
- A pre-commit scan in front of that, catching things before they are even committed
- A CI scan beside it, using a different engine — GitLeaks or TruffleHog — so a different pattern set gets a look
- Custom patterns for your own formats, because nothing else will find them
- Short credential lifetimes, so an undetected leak expires on its own
Secret scanning in CI assembles all of this into a single pipeline.
Enabling it, and what to expect
Section titled “Enabling it, and what to expect”For a public repository there is nothing to do — scanning is on. For a private or internal repository with GitHub Secret Protection available, it is a setting under the repository’s code security configuration, and it can be applied across an organisation through a security configuration rather than repository by repository.
Three things to plan for before switching it on across an established organisation:
The initial wave. Historical scanning surfaces years of accumulated findings at once. Decide who owns triage before the alerts arrive, not after.
Where alerts go. By default they appear in a tab. Route them somewhere the owning team actually looks — a notification, a chat channel, an issue — because the tab is not part of anyone’s day.
What “done” looks like. Zero open alerts is the wrong target if it is achieved by dismissal. A better one is zero active credentials, with every dismissal carrying a reason somebody else could evaluate.
Organisational view
Section titled “Organisational view”At scale, individual repository alerts are the wrong unit of work.
Security overview aggregates alerts across an organisation, which is where you see that one team has forty active alerts and another has none — usually a signal about enablement rather than about hygiene.
Secret scanning campaigns turn a filtered set of alerts into a tracked remediation effort with an owner and a deadline, rather than a list somebody is meant to get to. See Security campaigns.
Enablement policy matters more than either. An organisation where secret scanning is enabled on sixty percent of private repositories has a detection gap that no amount of triage discipline closes.
Common mistakes
Section titled “Common mistakes”Treating an alert as the problem rather than the symptom. The alert is a notification that a credential leaked. Closing it does nothing to the credential.
Rewriting history before rotating. The expensive half done first, while the credential stays valid. This is the most consequential ordering mistake in the pillar.
Assuming private repositories do not need it. Private restricts readership to a set that is larger and more mutable than people picture, and every clone keeps what it had.
Ignoring issue and pull request comments. A large share of real leaks arrive in a pasted error message, not in code.
Not writing custom patterns. If your organisation issues its own tokens, they are invisible until you describe them.
Dismissing without a reason. The reason is the record. Without it, the next person re-does the analysis or re-opens the argument.
Believing “secret” gists are private. They are unlisted. Anyone with the link can read one.
Mental model
Section titled “Mental model”Secret scanning detects credentials that may already exist in content. It is a smoke detector: it tells you something is burning, it does not put it out, and it only detects the kinds of smoke it was built for.
What you learned
Section titled “What you learned”- Secret scanning is detection; the credential is already committed and cloned when it fires
- It covers all branches and full history, plus issues, pull requests, Discussions, wikis and secret gists
- Partner patterns notify the provider directly, which is often the fastest remediation available
- Generic patterns trade precision for recall; AI detection covers unstructured credentials
- Custom patterns are the only way to detect credential formats your organisation invented
- Validity checks split the queue into “working credential” and “already dead”, which is the only triage split that matters
- Free and default-on for public repositories; private repositories need GitHub Secret Protection on Team or Enterprise
- Rotation comes first, history cleanup second, and closing the alert last
- A dismissal is a permanent decision with no expiry, so the reason is the whole record
Exercise
Section titled “Exercise”Use a public disposable repository, so scanning is enabled without a licence. Use only obviously fake values.
-
Create the repository and commit a file containing
EXAMPLE_API_KEY=not-a-real-credential-just-a-string. Predict: does this raise an alert? Check the security tab. -
Now commit a string in a recognisable provider format, using clearly invalid characters — a
github_pat_prefix followed by obvious filler. Predict: does the shape matter more than the validity? -
Open an issue whose body contains a similar fake credential. Predict: is the issue scanned?
-
For any alert raised, read whether validity was checked and what it reported.
-
Delete the file in a new commit. Predict: does the alert close?
-
Open the alert and read the dismissal reasons. Choose one and write a reason a stranger could evaluate.
-
Delete the repository.
Related lessons
Section titled “Related lessons”The secrets management checklist and least-privilege token guide are in the Professional Toolkit.