Secret Scanning, Push Protection, Custom Patterns, Bypass Controls, and Incident Response: Concepts, Architecture, and Mental Model
A credential leak is an authorization incident, not merely an embarrassing line in Git history. This lesson separates historical secret detection, pre-receive push protection, provider patterns, validity signals, bypass governance, and the incident-response sequence so learners know which control prevents exposure and which control contains damage after exposure.
Learning objectives
- Explain historical secret scanning versus push-time protection and identify which GitHub resource/state each control creates or changes.
- Distinguish provider/partner patterns, generic patterns, custom patterns, validity checks, and the false-positive problem.
- Differentiate user push protection from repository/organization protection and explain why bypass is a governed exception rather than a convenience button.
- Apply the response sequence revoke/rotate → assess use/scope → remove exposure → consider history rewrite → verify.
- Recognize non-Git secret locations such as issues, pull requests, Discussions, wikis, and secret gists when scoping an incident.
1. The problem: the secret is the security object, not the line of Git history
Chapter 20 taught how workflows should receive credentials. Chapter 24 handles the failure case: a credential appears somewhere it should not. The dangerous beginner instinct is to delete the line, amend the commit, and declare victory. That changes repository presentation, but it does not invalidate a copied credential. If an attacker, crawler, collaborator, log collector, fork, or provider has already seen the value, the credential remains usable until the issuing system revokes or rotates it.
GitHub therefore provides two complementary classes of control. Secret scanning searches existing content and creates evidence after a match is found. Push protection examines content at a write boundary and can block a secret before it reaches the repository. Neither replaces provider-side revocation. Detection tells you where the exposure is; the issuing provider controls whether the credential can still authenticate.
2. Mental model: prevention, detection, containment, cleanup
flowchart TD
W["Developer / API / GitHub UI write"] -->|candidate content| P["Push protection"]
P -->|safe| R["Repository / hosted surface"]
P -->|supported secret| B["Blocked write or governed bypass"]
R -->|historical + hosted-content scan| S["Secret scanning"]
S -->|match| A["Alert / partner notification"]
A -->|identify provider + owner| V["Revoke or rotate credential"]
V -->|contain and assess use| C["Incident evidence"]
C -->|remove exposed content if useful| H["Content cleanup / optional history rewrite"]
H -->|verify| Z["Closed incident + prevention improvement"]
The first arrow is a proposed write: a Git push, web edit/upload, or supported API operation. Push protection can stop that write before repository state changes. If content reaches a GitHub surface, secret scanning examines Git history and supported hosted content. A match creates a user alert, a push-protection alert, or a partner notification depending on the pattern and feature. The critical control then leaves GitHub: the credential issuer must revoke or rotate the secret. Only after access is contained do you decide how much repository cleanup is justified.
The last arrow matters operationally. “Closed” means the old credential is unusable, its possible use was assessed, dependent systems were migrated, residual exposed copies were handled, and prevention was improved. It does not mean the repository’s current default branch happens to look clean.
3. Secret scanning: historical and hosted-content detection
Secret scanning examines the entire Git history on all branches and rescans when GitHub adds new supported secret types. Current GitHub.com scanning also covers titles/descriptions/comments in issues and pull requests, GitHub Discussions, wikis, and secret gists. An incident responder must therefore ask “where is this credential visible?” rather than assuming every leak is a blob in a Git commit.
| Detection type | What it means | Operational consequence |
|---|---|---|
| Provider/user pattern | GitHub recognizes a credential format from a service/provider | A user alert may appear; triage provider, owner, location, validity and remediation. |
| Partner alert | A participating provider pattern is found in public content | GitHub can notify the provider directly; partner alerts are not necessarily shown as ordinary repository user alerts. |
| Generic pattern | A non-provider-specific secret shape such as a private key/connection string | Useful for broader detection; capability such as push protection/validity varies by pattern. |
| Custom pattern | Organization-defined regular expression for an internal secret format | Requires ownership/testing; false positives can become organization-wide delivery friction. |
| Validity check | GitHub asks a supported issuer whether a detected credential is still active | Prioritization signal, not permission to delay revocation when compromise is credible. |
A secret-scanning alert is a GitHub security object with state, type, locations, resolution, and sometimes validity/metadata. The alert is evidence about exposure; it is not the credential itself and should be retrieved with literal-secret hiding whenever possible.
4. Push protection: a write-path control
Push protection evaluates supported secret patterns before the write is accepted. Current GitHub behavior covers command-line pushes, commits and uploads in the web UI, supported REST writes, and some GitHub MCP interactions. A block means the repository has not yet accepted that attempted content. The safest response is to remove the value and retry; there is no security benefit to bypassing a known real secret merely because the secret will be rotated later.
| Mode | Scope | Default / availability | Bypass evidence |
|---|---|---|---|
| Push protection for users | Your account pushing to public GitHub.com repositories | GitHub.com only; enabled by default | If repository protection is not also enabled, a user bypass does not create the same repository alert trail. |
| Repository push protection | Specific repository, with Secret Protection | Available for public repositories; private/internal plan-dependent | Repository-level bypass creates secret-scanning evidence and requires a reason under the normal bypass flow. |
| Organization/enterprise policy | Many repositories through security configuration | Organization/enterprise administration and entitlement dependent | Can centralize patterns, bypass actors, exemptions, and review policy. |
5. Bypass is an exception workflow, not a detector failure
A false positive, a non-sensitive test value, or trusted migration automation can justify an exception. But routine bypass destroys the value of prevention. Repository push protection can require a reason, and delegated bypass can separate the person requesting an exception from the person approving it. Current delegated-bypass requests expire after seven days, which reinforces the idea that an exception is a short-lived decision, not permanent permission.
6. Read-only inspection before changing anything
Before enabling, disabling, or testing a protection, inspect the repository and account state. The UI remains useful because it exposes current Secret Protection configuration, while the REST repository object gives machine-readable security settings and the secret-scanning API gives alert state. Do not print literal secret values while inspecting alerts.
REPO=OWNER/REPO
gh repo view "$REPO" --json nameWithOwner,visibility,defaultBranchRef,url
gh api -H "X-GitHub-Api-Version: 2026-03-10" "repos/$REPO" \
--jq '{visibility,security_and_analysis}'
# When alert access is available, hide literal values in automation.
gh api --paginate -H "X-GitHub-Api-Version: 2026-03-10" \
"repos/$REPO/secret-scanning/alerts?hide_secret=true&per_page=100" \
--jq '.[] | {number,state,secret_type,validity,resolution,is_publicly_leaked,is_multi_repo,push_protection_bypassed}'
An empty alert list is evidence that the API returned no current matches under your visibility—not proof that no credential exists anywhere. A 404/403 can mean different things: unavailable feature, wrong repository, insufficient role/token permission, or product/version mismatch. Diagnose those before changing policy.
7. Incident response: the order is the control
| Order | Action | Why first/next |
|---|---|---|
| 1 | Identify provider, credential owner, permissions, locations and time window | You need to know what can be abused and who can revoke it. |
| 2 | Revoke or rotate the credential at the issuer | Stops future authentication even if copies remain in GitHub, forks, clones or logs. |
| 3 | Assess use and dependent systems | Look for unauthorized use; update every legitimate consumer so rotation actually completes. |
| 4 | Remove exposed current content and close obvious distribution paths | Reduce future discovery and accidental reuse after the credential is dead. |
| 5 | Decide whether history rewrite is warranted | History rewriting is disruptive and may not reduce risk once the secret is revoked. |
| 6 | Verify and improve prevention | Confirm old credential fails, new consumers work, locations are handled, alert state/rationale is durable, and push protection/pattern policy improves. |
8. Why this matters in DevOps
CI/CD systems concentrate credentials: package tokens, deployment identities, signing keys, webhook secrets, API credentials, and service accounts. A single leaked high-privilege credential can cross repository and environment boundaries. Secret scanning and push protection therefore sit at the same trust boundary as workflow permissions and runner isolation: they reduce the probability and blast radius of automation compromise.
The production objective is not “zero secret alerts at any cost.” It is a measurable system where supported writes are blocked early, alerts are triaged quickly, live credentials are revoked first, exceptions are auditable, non-Git surfaces are included in incident scope, and custom detection does not create more bypass behavior than it prevents.
Knowledge check
Why is deleting a leaked token from the latest commit not sufficient?
Because anyone who already copied it can still authenticate until the issuing provider revokes or rotates it, and older copies may remain in Git history, forks, caches, comments, or logs.
What is the difference between user push protection and repository push protection?
User push protection protects your pushes to public GitHub.com repositories and is on by default. Repository push protection is a repository security control under Secret Protection and creates richer repository-level governance/bypass evidence.
Why should automation request secret-scanning alerts with literal values hidden?
The alert metadata and locations are usually enough for triage; retrieving or logging the secret value creates a new exposure path.
Does a validity check mean an apparently inactive secret can be ignored?
No. It is a prioritization signal. You still need provider/owner confirmation, scope assessment, durable resolution evidence, and prevention review.
When is a bypass legitimate?
When an authorized policy determines the detected value is safe or an approved exceptional workflow requires it, with explicit reason/evidence and preferably independent review. Routine bypass is a control failure.
Summary
Secret scanning detects historical and hosted-content exposure; push protection prevents supported secrets from entering protected write paths; validity and pattern metadata help prioritize; bypass is an exception workflow; and the incident begins with provider-side revocation/rotation, not Git surgery.
Next you will exercise those boundaries in a disposable public repository using a GitHub-published dummy token that cannot authenticate.
Official references
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.