git-all-secrets: The GitHub Organization Secret Scanner That Time Forgot
Hook
In 2019, a single Docker command could scan every repository, gist, and team resource across your GitHub organization for leaked secrets. Four years later, we're still rebuilding the same orchestration layer.
Context
Before cloud-native development became ubiquitous, secret scanning was a manual afterthought. Developers would occasionally run tools like truffleHog against repositories they suspected might contain leaked credentials, but comprehensive organizational audits were rare. The problem wasn't just technical—it was operational. Even if you knew how to use truffleHog or repo-supervisor, how would you discover all repositories across your organization? What about gists? Team repositories? Private repos you didn't know existed?
git-all-secrets emerged to solve this enumeration problem. Written in Go by security researcher Anshuman Bhartiya, it combined GitHub's API with multiple open-source scanning engines to create what was essentially an organizational secret audit tool. Instead of manually tracking down repositories and running scanners individually, security teams could point git-all-secrets at an organization name and walk away. The tool would handle API authentication, repository discovery, cloning, scanning with multiple engines, and result aggregation. While the project hasn't been updated since 2019, its architectural approach to the enumeration problem remains instructive for anyone building security tooling today.
Technical Insight
The core innovation in git-all-secrets isn't the scanning itself—it delegates that to truffleHog and repo-supervisor—but rather the orchestration layer that sits above them. The tool's architecture reveals several thoughtful decisions about how to wrangle the GitHub API at scale.
At its heart, git-all-secrets is a state machine that progresses through four phases: authentication, enumeration, cloning, and scanning. The authentication phase uses GitHub personal access tokens to determine scope. If you provide a token with full repo access, it scans private repositories; otherwise, it limits itself to public resources. This graceful degradation means you can run quick audits without elevated permissions, then re-run with a privileged token for comprehensive coverage.
The enumeration phase is where things get interesting. Here's a simplified view of how the tool discovers repositories:
// Pseudo-code based on git-all-secrets architecture
func enumerateTargets(config Config) ([]Repository, error) {
client := github.NewClient(config.Token)
var repos []Repository
switch config.ScanType {
case "org":
// Get all org repos
orgRepos := client.Organizations.ListRepos(config.OrgName)
repos = append(repos, orgRepos...)
// Get all org members
members := client.Organizations.ListMembers(config.OrgName)
for _, member := range members {
// Get each member's repos
memberRepos := client.Repositories.List(member.Login)
repos = append(repos, memberRepos...)
// Get public gists
gists := client.Gists.List(member.Login)
repos = append(repos, gists...)
}
case "user":
userRepos := client.Repositories.List(config.UserName)
repos = append(repos, userRepos...)
}
return deduplicateRepos(repos), nil
}
This enumeration strategy is aggressive by design. When you scan an organization, you're not just getting the org's repositories—you're also scanning every public repository and gist from every organization member. This broad net catches scenarios where developers accidentally commit secrets to personal repos while working on company projects, a surprisingly common attack vector.
The cloning phase uses a clever workaround for private repository access. Rather than handling SSH key management in Go (which is notoriously complex), git-all-secrets runs inside a Docker container and expects you to mount your SSH keys as a volume:
docker run --rm -it \
-v ~/.ssh:/root/.ssh \
abhartiya/tools_gitallsecrets \
-token=$GITHUB_TOKEN \
-org=mycompany \
-output=/tmp/results.json
This design choice reveals a pragmatic understanding of deployment contexts. Rather than reimplementing SSH authentication, the tool delegates to the system's existing SSH agent and key infrastructure. It's less portable than a pure-Go solution, but far more reliable in practice.
The scanning phase demonstrates effective concurrency patterns. The tool spawns goroutines for each repository, controlled by a thread limit flag (defaulting to 10). Each goroutine clones a repository, runs both truffleHog and repo-supervisor against it, then aggregates results into a unified JSON structure:
type ScanResult struct {
RepoName string `json:"repoName"`
RepoURL string `json:"repoUrl"`
TruffleHog []Secret `json:"truffleHog"`
RepoSupervisor []Secret `json:"repoSupervisor"`
}
type Secret struct {
Commit string `json:"commit"`
Branch string `json:"branch"`
FilePath string `json:"filePath"`
Reason string `json:"reason"`
}
What's notable here is the dual-scanner approach. By running both truffleHog (regex and entropy-based detection) and repo-supervisor (pattern matching), the tool increases coverage while allowing analysts to compare findings. If both scanners flag the same string, confidence is high. If only one scanner triggers, it might warrant additional scrutiny.
The tool also includes an -entropy flag to disable truffleHog's entropy checking. This seemingly minor feature reflects real-world experience: entropy-based detection generates enormous amounts of noise in large organizations, flagging everything from encoded images to compressed data. The ability to toggle it off transforms the tool from unusable to practical for large-scale audits.
Gotcha
The elephant in the room is maintenance. git-all-secrets hasn't been updated since 2019, and the gap shows in several areas. The underlying truffleHog version it uses is v1, which has since been completely rewritten from scratch. TruffleHog v3 is faster, more accurate, and supports many more secret types, but git-all-secrets can't leverage any of those improvements without significant refactoring.
The team scanning functionality is marked as experimental in the documentation, and for good reason—GitHub's Teams API has evolved considerably since 2019. The tool may fail or produce incomplete results when scanning team repositories, particularly in organizations using GitHub's newer team synchronization features.
There's also no incremental scanning capability. Every run performs full clones of every repository, which becomes prohibitively expensive for large organizations. If you're monitoring an organization with 500+ repositories, you're looking at potentially gigabytes of cloning overhead and hours of scan time. Modern alternatives maintain state and only scan changed files, making them orders of magnitude faster for continuous monitoring scenarios. The lack of caching or differential scanning means git-all-secrets is strictly a point-in-time audit tool, not a continuous monitoring solution.
Verdict
Use if: You need to perform a one-time comprehensive audit of a GitHub organization's secret exposure and want the simplest possible workflow. The Docker-based deployment eliminates dependency hell, and the enumeration logic still works reliably for discovering all organizational attack surface. It's also valuable if you're specifically comparing results across multiple scanning engines or researching how different tools detect different secret types. Skip if: You're building a continuous monitoring pipeline, need integration with modern CI/CD systems, or require up-to-date secret detection patterns. The 2019 vintage means you're missing four years of new secret types, API tokens, and detection improvements. For production use, migrate to Gitleaks for pre-commit scanning, TruffleHog v3 for repository scanning, or GitGuardian for comprehensive secret management. The architectural lessons from git-all-secrets—particularly around GitHub API enumeration and multi-scanner orchestration—remain valuable, but the implementation itself has been superseded by actively maintained alternatives.