In July 2026, GitHub published a rare piece of self-reporting: its own security team had spent nine months clearing out more than 20,000 secret scanning alerts spread across over 15,000 internal repositories. The alerts were generated by GitHub Advanced Security's own secret scanning feature — the same product GitHub sells to customers — running against GitHub's own codebase. Staff Security Engineer Michael Recachinas wrote up how the team went from a backlog nobody trusted to zero open alerts, and kept it that way. The headline number that should worry every AppSec team running a similar program: roughly 90% of those 20,000+ alerts turned out to be noise, concentrated in just five repositories full of test fixtures and dead credentials. That ratio — thousands of real signals buried under tens of thousands of false ones — is the textbook definition of secret scanning alert fatigue, and it's why so many programs quietly stop triaging altogether.
What did GitHub's secret scanning backlog actually look like?
It looked like more than 20,000 open alerts across 15,000+ repositories, and almost nobody had a clear read on how many of them mattered. GitHub had enabled secret scanning broadly, but enabling a scanner and operationalizing its output are different problems. Alerts accumulated over years, ownership metadata was inconsistent, and — as Recachinas describes it — many alerts pointed to services where "durable ownership" had never been established in the first place. Some secrets lived in places a code scanner never checks at all: support tickets, bug bounty submissions, incident notes, and internal wiki pages. The backlog wasn't just large, it was structurally hard to reason about, which is precisely the condition that produces alert fatigue: security teams stop opening the queue because opening it doesn't tell them what to do next.
Why were 90% of the alerts false positives?
Because roughly 18,000 of the 20,000+ alerts traced back to just five repositories containing test fixtures and inactive credentials, not five different problems spread evenly across the estate. GitHub's triage phase categorized every alert by repository, secret type, and age before touching remediation, and that categorization step alone surfaced the concentration. Once the team could see that a handful of repos accounted for nearly nine in ten alerts, they could bulk-close that noise in a single pass instead of triaging it one alert at a time. That left roughly 2,000 alerts that actually warranted human attention — a number small enough to route, own, and close. The lesson generalizes past GitHub: alert-fatigue math is rarely "we have too many secrets," it's "we have a small number of repositories generating almost all the noise, and we're triaging them as if each alert were independent."
How did GitHub separate real risk from dead credentials?
By building a validity check that answered the only question that matters — is this credential still active — instead of relying on humans to guess from context. For GitHub-issued tokens, the team built a representative check that could make a single authenticated, low-impact API call, such as a GET /user request, to confirm whether a flagged token was still live. A token that fails that check is noise; a token that succeeds is a live production risk with a name attached. GitHub later folded this validity-checking capability into the product itself, which is telling: the internal fix for their own alert fatigue became a shipped feature, because "is this secret still valid" turned out to be the single highest-leverage question a scanner can answer before a human ever sees the alert.
How did GitHub get alerts to the right owner without chasing people down?
By tying every alert to a service owner through GitHub's Engineering Fundamentals program and automating the notification instead of emailing individuals. Engineering Fundamentals is GitHub's internal standards program that enforces durable service-to-repository ownership mappings across the company — the same mapping problem that had been missing for years and that made early alerts orphaned. Once ownership existed as a queryable fact, GitHub could automate routing: alerts went to the team that owned the repository, secret-type-specific playbooks told that team exactly what to do, and remediation got tracked as a measured engineering fundamental rather than a security-team favor. That reframing mattered as much as the automation — a metric a team is graded on gets fixed faster than a ticket a team can decline.
How did GitHub make "inbox zero" stick instead of refilling immediately?
By treating disposition, not deletion, as the closing criteria, and by pushing detection upstream with push protection so new secrets stopped landing in the first place. GitHub's team documented explicit rules for edge cases: secrets found in issues were preserved for audit trails rather than scrubbed, deleted repositories were archived instead of purged to keep forensic records intact, and git history rewriting was reserved for cases where rotation alone wasn't sufficient. Alerts also got routed into GitHub's internal vulnerability management platform so that "closed" meant tracked-and-resolved, not "we stopped looking." Combined with organization-wide push protection that blocks known secret patterns before a commit lands, the nine-month cleanup became a floor, not a one-time reset — which is the difference between reaching inbox zero and reaching inbox zero again next quarter.
How Safeguard Helps
GitHub's own writeup is effectively a case study in what happens when scanning coverage outpaces triage capacity — a pattern Safeguard sees constantly in customers running GitHub Advanced Security, Semgrep, or open-source scanners like Gitleaks and TruffleHog across large repository fleets. The scanner finds the secrets; almost nothing in that stack tells you which 10% deserve a human's attention today. Safeguard is built to close that specific gap rather than add another scanner to the pile.
- Automatic validity checking at ingestion. Safeguard correlates secret scanning findings from GitHub Advanced Security and other tools against live credential-validity checks — the same "is this token still active" question GitHub had to build custom tooling to answer — so dead test-fixture credentials never reach a human queue in the first place.
- Ownership resolution out of the box. Rather than requiring a company-wide Engineering Fundamentals-style program before alerts can be routed, Safeguard maps findings to repository owners, CODEOWNERS entries, and service catalogs automatically, so a 15,000-repo estate doesn't need a nine-month internal initiative just to know who to notify.
- Noise concentration analysis. Safeguard surfaces exactly the pattern GitHub found manually — that a small number of repositories (often test fixtures, forks, or archived projects) generate the overwhelming majority of alerts — so teams can bulk-triage the 90% and focus analyst time on the 2,000 that matter, without a bespoke categorization project.
- Cross-surface secret detection. Because secrets don't only live in code, Safeguard extends detection and correlation to adjacent surfaces like CI/CD logs, container images, and infrastructure-as-code, addressing the same class of blind spot GitHub called out around tickets, wikis, and incident notes.
- Playbook-driven remediation, not ticket sprawl. Findings come with secret-type-specific remediation guidance and rotation workflows baked in, so teams get GitHub's playbook approach without having to author it themselves.
Secret scanning alert fatigue isn't a GitHub problem or an Advanced Security problem — it's what happens anywhere detection scales faster than triage. GitHub had the engineering resources to spend nine months building custom validity checks and an ownership program from scratch. Most teams don't have that runway, which is exactly why Safeguard exists: to deliver GitHub's inbox-zero outcome — real alerts routed to real owners, false positives filtered before they're ever seen — as a product, not a nine-month internal project.