◀ Playbook index
NO.19.4

Secret Scanning

Updated: 2026-10-27

In a nutshell

Secret Scanning is GitHub's detection feature that automatically finds API keys, tokens, and connection strings lurking in your repository.

Secrets already committed get an alert; secrets about to be pushed are blocked at git push time by Push protection. Stopping leaks before they happen is the core strategy.

Why secrets matter in private / internal repos

Private does not mean the breach stays contained. An attacker who compromises one developer account or runner can use internally exposed secrets to expand the attack. Keep secrets in a secret manager and block leaks with Push protection. Here are 8 reasons why.

▸ CLICK + TO REVEAL

01Internal repos, external developers

An internal repo does not mean an internal-only workforce. Employees, contractors, systems integrators, and subcontractors with read access can all read committed secrets. Outsourcing extends access beyond your own employees and the devices you manage.

02One click from public

A misclick, repo transfer, Org misconfiguration, or policy change flips it public. Attacker scanners detect new public repos within seconds; leaked tokens have been abused within 60 seconds.

03Git history is forever

Deleting it in a later commit does not remove it. It stays in history, every local clone, forks, backups, and CI caches. The only fix is rotation, not file deletion.

04Git distributes your secrets, too

Git is a distributed version control system. A normal git clone copies code and history, including committed secrets, onto each developer's workstation, whether employee or contractor. Protecting the server is not enough. Revoking repo access when a contract ends does not erase those local copies.

05Account compromise = instant access

One phished developer exposes every secret in every repo they can read. The secrets themselves have no extra protection (no MFA, no self-managed encryption at rest, no expiry).

06Privilege escalation and lateral movement

Once inside your network, attackers can steal secrets from private / internal repos to gain higher privileges and move into production, cloud, or artifact registries. One compromised account can become an organization-wide breach, without any repo ever going public. MITRE ATT&CK ↗

07Compliance and audit

ISO 27001, SOC 2, PCI-DSS, and ISMAP require central management, rotation, and access tracking. Plaintext secrets in Git fail all three, and audit findings are guaranteed.

08The real cost of an incident

Emergency rotation, production outage, forensics, customer notification. Compare that to the 30 minutes it takes to set up a secret manager.

Main capabilities

DEMOSecret ScanningFOR PRESENTER ONLY
  1. PUSH PROTECTION

    In ghas-test-1, push a generated secret.

    ./demo/secret-scanning/01-push-protection.sh

    The push is blocked and the terminal prints an unblock URL.

    Show which patterns are push-protected, enterprise-wide: octodemo → Pattern configurations ↗. Flip a pattern in the Enterprise setting column; the Alert total, False positives, and Bypass rate columns back the noise-vs-risk call with real data.

    Jump directly to patterns disabled by GitHub default ↗. The filter is github-default:disabled: it filters GitHub defaults, not the current enterprise setting.

    Same page is revisited on the What gets detected slide, to dig out the generic patterns.

  2. BYPASS PUSH PROTECTION

    Open the unblock-secret URL from the block message in your browser, pick a reason and bypass.

    The reason decides what happens to the alert: It's used in tests creates a closed alert (resolved as "used in tests"), so nothing is left to triage. I'll fix it later creates an open alert that stays until someone revokes or rotates the secret.

    You get “secret can now be pushed”.

    Push the same branch again.

    git push origin HEAD

    Open the resulting alert under Security → Secret scanning and show who bypassed it and why.

    To keep bypasses under control: open ghas-test-1 → Advanced Security ↗, then set Push protection → Who can bypass push protection for secret scanning to Specific roles or teams (= Delegated bypass).

    Configure it across the org: open theomonfort-org → Security configuration ↗, set Push protection to Enabled and Bypass privileges to Specific actors, then select the actors. Click Save configuration and apply it to the target repos. Configuring delegated bypass at the org / enterprise level disables the repo-level setting.

    Demo the request flow as a contributor without bypass privileges (org owners / security managers can always bypass). Submit a request with a justification from the block page; reviewers receive an email notification.

    Review requests: ghas-test-1 → Push protection bypass requests ↗ (Security and quality → Requests → Push protection bypass). Filter by All statuses → Open, open a request, and show Approve bypass request / Deny bypass request. After approval, the requester pushes again.

    Gate the merge too: in ghas-test-1 → New branch ruleset ↗, turn on Require secret scanning alerts are resolved (Preview).

    An I'll fix it later secret is still an open alert, so the PR merge is blocked. It's used in tests doesn't block.

  3. VALIDITY CHECK

    In the default view under Security → Secret scanning, use the Validity filter.

    Triage by real risk: start with the secrets that are still live.

Push protection checks pushes to all branches on GitHub, not local commits at commit time. Merge protection checks before PR merge.

▸ CLICK + FOR DETAILS

Push protectionAt git pushDocs

What it doesRejects the push on the spot when it contains a secret. Bypass is possible, but the reason is recorded

ScopePushes to all branches of a GitHub repository where protection is enabled. Unpushed local commits are not covered. AI-detected secrets: separate opt-in toggle, private preview (invited orgs only)

Merge protectionBefore PR mergeChangelog

SetupAdd Rulesets → Require secret scanning alerts are resolved (Repo / Org / Enterprise)

Merge gateHead scan complete, no open PR-introduced alerts. Public preview, Secret Protection / GHAS. Ruleset bypass applies

Use caseExclude generic patterns from push protection, but include them in this ruleset: allow the push, require alert resolution before merge

Secret scanning alertsAfter commit, continuousDocs

What it doesNotifies you of detected secrets in the Security and quality tab

ScopeFull Git history on all branches, Issues, PRs, GitHub Discussions, Wikis, secret gists. Rescanned as new secret types ship

Validity checksWhen an alert firesDocs

What it doesAsks the provider API whether the secret is still active, so you can triage by real risk

ScopeSelect supported providers (AWS, GitHub, Slack, and others). AI-detected passwords are not covered (no provider to ask)

Partner programAlways on, public reposDocs

What it doesWhen a partner secret leaks, GitHub reports it straight to the provider, who revokes or reissues it

ScopePublic repos and public npm packages only. Reports never appear in your alert list (free, not configurable)

Public monitoringReal-time across github.comDocs

What it doesDetects secrets leaked outside your own repos (personal forks, OSS, public issues and PRs) and attributes them to your enterprise

ScopePublic content only, and it never scans private repos. GHEC Enterprise

What gets detected

DEMODetection typesFOR PRESENTER ONLY
  1. WHERE THE GENERIC PATTERNS HIDE

    Open octodemo → Patterns disabled by GitHub default ↗, prefiltered with github-default:disabled.

    It is one flat list, with no generic label. This filter matches the GitHub default value; it is not a generic-only filter.

    Point them out by name — these ten are the entire set:

    rsa_private_key openssh_private_key ec_private_key pgp_private_key generic_private_key mongodb_connection_string mysql_connection_url postgres_connection_string http_basic_authentication_header http_bearer_authentication_header

    Every one reads Disabled under GitHub default: detection is on, but push protection is off by default.

  2. CUSTOM PATTERN + DRY RUN

    Open ghas-test-1 → New pattern ↗ (Settings → Advanced Security → Custom patterns → New pattern).

    Matching secrets are already planted in the demo repo, so you only need to create the pattern:

    Pattern name — Octodemo internal service token

    Secret format — octodemo_(live|test)_[A-Za-z0-9]{32}

    Test string — octodemo_live_L1QNGy4DLxQJ8C85kfwP0lmvCHLDuVxJ

    The test string has to go green before the form will save. Then use Save and dry run.

    The dry run reports the planted secrets without creating alerts. Review the hits, then Publish pattern.

  3. ENABLE GENERIC / CUSTOM PATTERNS

    Open octodemo → Pattern configurations ↗.

    Generic: In Default patterns, find a pattern such as rsa_private_key and set Enterprise setting to Enabled.

    Custom: Switch to Custom patterns, choose a published enterprise pattern, and set Enterprise setting to Enabled. For the repository-scoped pattern created above, use Push protection → Enable in that repository's custom pattern settings instead.

    This enables push protection, not detection. New pushes containing a matching secret are blocked when the demo repository also has push protection enabled and no organization override disables the pattern.

Four detection engines, layered from exact partner formats to unstructured secrets that only AI can catch.

▸ CLICK FOR DETAILS

Provider patterns

Provider patterns

Regex patterns registered by 200+ partners including AWS, Azure, GCP, Stripe, Slack, OpenAI, and GitHub PATs. Extremely low false-positive rate.

📘 Supported secrets ↗

Generic patterns

Generic patterns

Private keys, connection strings, HTTP basic auth, and other generic formats. A wider net by design, so expect more triage than provider patterns. Not push-protected by default — opt each pattern in under Pattern configurations.

AI-detected secrets

AI-detected secrets

Uses AI to detect unstructured secrets such as passwords, covering the ground no regex can reach. Push protection is a separate toggle in private preview (invited orgs only). No validity checks, so triage these as alerts.
🔎 Alerts show up in the Generic tab.

Custom patterns

Custom patterns

Define regexes for your own token formats: internal service tokens, legacy credentials, anything a partner will never register.
🔎 Listed under Default; filter by Secret type.

📘 Defining custom patterns ↗

SELECT A TYPE ▸

How to manage exposed secrets

DEMOSecurity campaignsFOR PRESENTER ONLY
  1. THE CAMPAIGNS TAB

    Open theomonfort-org → Campaigns ↗.

    The tracking view: each campaign with its due date, manager, and a burn-down of open vs closed alerts. The point to land: alerts get an owner and a deadline here, not in a spreadsheet.

  2. CREATE ONE FROM SECRET SCANNING FILTERS

    Create campaign → From secret scanning filters

    Build the filter live so they see the triage logic. Start from is:open, narrow to the repos that matter, then set Validity to Active and Unknown.

    Watch the alert count drop with each filter. That is the whole argument: a finishable list instead of a backlog. Must be 1000 alerts or fewer to save.

  3. NAME IT, DATE IT, SHIP IT

    Save as → Draft campaign, then fill in the name, description, due date, and campaign manager.

    Note the manager picker only offers org owners and security managers.

    Review and publish notifies everyone who can see the alerts, and the campaign shows up in each repo's Security tab. Mention secret campaigns are in public preview.

When a secret is found, remediation matters more than detection. At scale, don’t work the raw alert list, run it as a security campaign.

▸ CLICK A STEP FOR DETAILS

SCOPE

🎯 SCOPE — critical repos first

Org → Security and quality → Campaigns → Create campaign → From secret scanning filters

Not the whole org. Target the repos that matter, for example with a repository custom property (props.BusinessPriority:Urgent). Cap it at 1000 alerts, which is also the hard limit.

TRIAGE

⚡ TRIAGE — by real risk

Filter validity to Active and Unknown. Active is a live key someone can use right now. Unknown means nobody could confirm it is dead, so treat it as live.

Inactive can wait. This is what turns a backlog into a list worth someone's week.

OWN

👤 OWN — a name and a date

Every campaign gets a due date and a campaign manager. The picker only offers org owners and security managers.

Without both, nothing gets rotated. Publishing notifies everyone who can see the alerts, and the campaign appears in each repo's Security tab.

ROTATE

🚨 ROTATE — then close it out

Deleting it from the repo is not enough: it stays in the history and in everyone's clones.

Partner secrets leaked in public repos are revoked provider-side and never reach your alert list. Then close each alert as Revoked, False positive, or Used in tests so the campaign burns down.

SELECT A STEP ▸

DEMOSecret Scanning checklistFOR PRESENTER ONLY
  1. 1. INTERNAL SECRET PATTERNS

    ghas-test-1 → New custom pattern ↗: show Secret format, Test string, then Save and dry run before publishing.

  2. 2. PUSH PROTECTION PATTERNS

    octodemo → Pattern configurations ↗: review False positives, Bypass rate, and the Enterprise setting column.

  3. 3. DIFFERENT RULES BEFORE MERGE

    ghas-test-1 → New branch ruleset ↗: Require secret scanning alerts are resolved → Generic patterns. Target main; keep the ruleset disabled for a walkthrough.

  4. 4. PUSH PROTECTION BYPASS

    octodemo → Security configurations ↗: open the intended configuration, then Push protection → Bypass privileges → Specific actors.

    Enterprise settings can affect other repositories. Do not save or apply changes during a read-only demo.

  5. 5. SECRET REMEDIATION CAMPAIGN

    theomonfort-org → Campaigns ↗: Create campaign → From secret scanning filters. Scope to ghas-test-1 and save as a draft.

    ghas-test-1 → Secret scanning alerts ↗

  6. 6. STORE WORKFLOW SECRETS

    ghas-test-1 → Actions secrets ↗: show New repository secret. Do not enter a real secret during screen sharing.

With Secret Protection and push protection enabled, this is the order I recommend.

▸ CHECK COMPLETED STEPS. OPEN A STEP FOR SETTINGS

1Add patterns for internal secrets, if anyCUSTOM PATTERNSDocs

ConfigureNew custom pattern ↗: dry-run your token formats, then publish.

2Choose what push protection blocksPATTERNSDocs

ReviewPattern dashboard ↗: check false positives and bypass rates, then choose which patterns to block.

3Add different rules before mergeMERGE PROTECTIONDocs

ExampleRulesets ↗: Require secret scanning alerts are resolved → Generic patterns. Allow push; resolve alerts before merge to main. Separate ruleset bypass. Public preview.

4Choose who can bypass push protectionENTERPRISEDocs

RestrictEnterprise configurations ↗: Bypass privileges → Specific actors. Save and apply the configuration.

5Create a campaign for existing secretsCAMPAIGNSDocs

RemediateSecurity campaigns ↗: select secret scanning alerts, assign owners and a deadline, then revoke or rotate.

6Store workflow secrets in GitHub, not codeACTIONS SECRETSDocs

StoreActions secrets ↗: Settings → Secrets and variables → Actions → New repository secret.

URL templates: replace ENTERPRISE, ORG, OWNER, REPO.

Availability by product

Feature Public repo Private / internal
without product
Secret Protection / GHAS
Secret scanning alerts✅ Free❌✅ Included
Push protection (repo / org)✅ Free❌✅ Included
Partner program alerts (sent to the provider)✅ Free, always on❌❌ Public repos only
Validity checks❌❌✅ Supported providers
Generic patterns❌❌✅ Included
Custom patterns❌❌✅ Included
AI-detected secrets❌❌✅ Included
Public monitoring❌❌✅ GHEC Enterprise

🆓 User push protection is free and enabled by default on all plans, but only covers pushes to public repositories. Partner alerts also notify providers only about leaks in public repositories and public npm packages — always on, and not configurable.

👤 User-owned repositories are a special case: alerts require GHEC with Enterprise Managed Users, or GHES with Secret Protection enabled on the enterprise. Org-owned private / internal repos only need Secret Protection on Team or GHEC.

💰 Generic, custom, and AI detection, validity checks, and private / internal repository coverage require Secret Protection or a legacy GHAS license. Public monitoring is an enterprise-wide feature for GHEC Enterprise.

📘 Details: Advanced Security products ↗ / Partner program ↗ / Public monitoring ↗

Public monitoring (NEW) 📖 Docs

  • 🌐 Public only — git, PR comments, issues, discussions. Never your private repos.
  • ⚡ Real time. Needs Secret Protection or GHAS. Public preview, no extra cost.
  • 🧩 No setup — enable it and existing findings appear straight away.
Attributed byWhat it checksCatches
👤 MemberCommitter is a memberManaged and known accounts
🌐 Verified domainEmail on your domainPersonal account, work email

⚙️ Turned on under Security and quality, by an enterprise owner or security manager.

Secret Risk Assessment 📖 Docs

Scans every org repo to show what secrets sit where. Free for Team and Enterprise orgs.

  • 🔎 Scope — every repo, any visibility, archived included
  • 📊 Output — secret types and counts per repo. Values are never stored or shown.
  • 🕒 Frequency — point-in-time, rerunnable every 90 days. Not continuous monitoring.
  • 🚀 Run it — Org → Security and quality → Assessments → Scan your organization. The first run also starts the free code security assessment.

📊 Answers “how many secrets are leaking?” and gives you the numbers for a budget case.

Slides 日本語