Security teams should treat deleted and private commits as part of the secret exposure surface, not as erased history. The practical approach is to enumerate reachable commit objects, scan them for credentials, and preserve restartable state so long searches can resume. Because GitHub rate limits apply, the process is slower than normal repo scanning and needs controlled batching and valid repository access tokens.
Why Deleted and Private Commits Still Matter
Deleted commits are not the same as destroyed evidence, and private repositories are not a safe assumption for secret hygiene. If a commit object remains reachable through Git history, forks, refs, caches, mirrors, or an access window that existed before deletion, the secret may still be retrievable and still valid. That makes commit scanning part of exposure management, not just code review. GitGuardian’s 2026 research found that internal repositories are 6x more likely to contain secrets than public ones, which is a useful reminder that private does not mean low-risk.
Teams often miss this because they scan only the current branch tip or only the active repository view. That leaves hidden history, dangling objects, and older private snapshots outside the scan path. A better mental model is that Git history is an attack surface with multiple retrieval paths, and every path that can reconstruct the object graph can also reconstruct leaked credentials. In practice, many teams discover the problem only after a token has already been propagated into multiple copies of the repository history.
How to Scan the Full Commit Graph Without Gaps
The practical unit of work is the reachable commit object, not the visible branch. Security teams should enumerate refs, walk the commit graph, and scan each object that can still be fetched or reconstructed. That includes private repos, deleted branches, merge commits, and historical snapshots captured by mirrors or CI systems. When the repository is large or access-limited, the scan must be restartable so a rate limit, token expiry, or interrupted job does not silently create a coverage gap.
For GitHub-specific workflows, the access model matters as much as the scanner. Use valid repository-scoped tokens, batch requests conservatively, and treat API throttling as an expected operating condition rather than an exception. The scan should preserve state for already-checked objects, record which refs were reachable at the time of collection, and retry only the missing segments. That makes the process auditable and prevents teams from assuming completeness when they only have partial coverage.
- Start from all reachable refs, then expand into commit ancestry instead of scanning only the latest revision.
- Track object IDs and scan status so interrupted jobs can resume without duplicating work.
- Include deleted or unreferenced history that is still reachable through replication, forks, or cached clones.
- Use repository access that matches the scope being scanned, because incomplete authorization can hide exactly the history you need to inspect.
NHIMG’s The State of Secrets Sprawl 2026 is useful context here because it shows how quickly secret exposure continues to scale in GitHub history. These controls tend to break down when organisations rely on a single pass over the live default branch because deleted objects, private forks, and historical rewrites remain outside that narrow view.
Where the Approach Breaks Down in Practice
Stricter scanning often increases execution time and access complexity, so teams need to balance completeness against GitHub rate limits, retention windows, and operational cost. The main failure mode is false confidence: a job reports success even though it never traversed every reachable object or it skipped private history that required a different token scope.
There is also a lifecycle problem. If a secret is found in old commits but not revoked, the scan has only documented exposure, not reduced it. Current guidance suggests treating detection and revocation as linked outcomes, because a valid credential in an old commit remains usable until the backend system invalidates it. The same is true for tokens that were copied into issue trackers, build logs, or release artifacts; commit scanning helps, but it does not close the full exposure path by itself. External guidance from the CISA cyber threat advisories is useful for understanding how exposed credentials are typically operationalised after discovery.
Risk and Threat Considerations
Hidden commit history creates a persistence risk for secrets that teams believe they removed. The material exposure is not just disclosure, but reuse: once an attacker or insider can recover an old token, the secret may remain valid long after the repository change that was supposed to remove it.
Failure mechanism: Attackers and researchers can recover credentials from reachable Git objects, forks, mirrors, cached clones, or incomplete scans that stop at the current branch tip. If scanning misses deleted or private commits, the organisation may believe rotation is complete while the credential still exists in recoverable history.
Impact: The consequence is downstream account compromise, API abuse, CI/CD access, or lateral movement through connected systems that trust the leaked secret. A single missed historical object can therefore preserve an active attack path even after the visible leak has been “fixed.”
Standards & Framework Alignment
This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.
MITRE ATT&CK address the attack and risk surface, while CIS Controls v8 and NIST CSF 2.0 set the governance and control requirements practitioners need to meet.
| Framework | Control / Reference | Relevance |
|---|---|---|
| CIS Controls v8 | 6 — Access Control Management | Scope access to repo history and reduce overbroad retrieval paths. |
| 8 — Audit Log Management | Historical commit scanning depends on preserving evidence of what was checked. | |
| 3 — Data Protection | Secrets in old commits remain sensitive data until found and revoked. | |
| Recommendation — Restrict repository and token access to the minimum scope needed for historical scanning. Log scanned object IDs, refs, and completion state to prove coverage. Classify and protect repository history that may still contain exposed credentials. | ||
| NIST CSF 2.0 | DE.CM — Continuous Monitoring | Ongoing scanning is needed to detect secrets that persist in hidden Git history. |
| PR.AC — Identity Management, Authentication and Access Control | Scanning private or deleted history requires controlled, verifiable repository access. | |
| PR.DS — Data Security | Exposed secrets in commits are sensitive data that require protection and remediation. | |
| Recommendation — Continuously monitor historical repository content for credential exposure. Enforce least-privilege access for tools that enumerate commit history. Protect historical repository data and revoke exposed secrets promptly. | ||
| MITRE ATT&CK | T1552.001 — Unsecured Credentials: Credentials In Files | Hardcoded secrets in commits are a classic credentials-in-files exposure pattern. |
| T1213 — Data from Information Repositories | GitHub history is an information repository attackers can mine for secrets. | |
| T1078 — Valid Accounts | Recovered secrets often enable valid account abuse after discovery. | |
| Recommendation — Hunt for credentials stored in repository files and commit history. Search repository history as a source of exploitable credential material. Treat any discovered secret as a potential valid-account path until revoked. | ||
Practitioner Guidance
What to prioritise: Prioritise reachability over recency. If a commit object can still be fetched or reconstructed, it belongs in scope even when the branch was deleted or the repository is private.
What to verify: Verify that the scanner records object IDs, repo scope, and completion state, then confirm that revoked or rotated credentials are not merely detected but actually invalidated at the source system. If the repository history is large, test a resume path before relying on the job in production.
Common mistake: Treating “no secrets found” as proof that no secrets exist is the classic error here. The more reliable question is whether the scan truly covered every reachable historical object under the current access model, including the ones GitHub rate limits made inconvenient to collect.
Practitioner takeaway: Hidden commit scanning is only trustworthy when completeness is measurable; if you cannot prove which objects were reachable and checked, you do not have a full exposure assessment.
Related resources from NHI Mgmt Group
- How should security teams implement secrets management across the SDLC without creating onboarding friction or hidden misconfigurations?
- How should security teams scan Elasticsearch for secrets without creating duplicate work or noise?
- How can security teams reduce attack surface without slowing operations?
- How should security teams test large applications and APIs without missing hidden risk?