Map out a GitHub org's public footprint (org + contributor repos) and scan it with TruffleHog
Project description
ghscan
A recon/scanning tool for GitHub organizations. Point it at an org and it will:
- enumerate every public repo the org owns
- figure out who's contributed to those repos (or, in "org-members" mode, pull the org's actual member list instead)
- enumerate every public repo each of those people personally owns
- dedupe everything into one scan queue
- run TruffleHog's
--only-verifiedmode against every repo in that queue - spit out a report of anything it found
An org's real secret-leak exposure isn't just its own repos, it's also
every employee's personal side-projects that happen to include a
copy-pasted API key or an old .env file. This tool maps that whole
footprint and scans it in one pass. Only point it at orgs/repos/accounts
you own or are explicitly authorized to test -- see LICENSE.md.
Everything is cached in a local SQLite file as it goes, so a run can be killed (Ctrl-C, a crash, whatever) and picked back up later without re-querying the API or re-scanning repos it already finished.
Requirements
- Python 3.9+
- TruffleHog installed
and on your
PATH(or pass--trufflehog-pathto point at it) - A GitHub personal access token with at least public read access (optional -- see below)
Install
pip install ghscan
Or from source:
git clone https://github.com/m4gester-bitt/ghscan.git
cd ghscan
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
Either way, make sure you cd into the folder you cloned/unzipped
before running anything below if you're on the source install -- the
commands assume you're already inside it.
Quick start
export GITHUB_TOKEN=ghp_yourtokenhere
ghscan --org some-org
That runs with the defaults: skips archived repos and forks, derives contributors from commit history, no volume caps. For a first look at a big org, it's worth doing a dry run first:
ghscan --org some-org --dry-run
This runs discovery, builds the scan queue, prints roughly how many repos it would scan and how many API calls that took, then stops before touching TruffleHog at all.
Running without a token
Don't need GITHUB_TOKEN set anymore to start it up. If it's missing it just asks:
No GITHUB_TOKEN environment variable detected.
Would you like to enter one now? [Y/n]
Say yes, type it in (hidden like a password), it carries on. Say no and it checks once more:
Are you sure you want to continue with no GitHub token? [y/N]
Confirm and it runs unauthenticated (60 req/hr cap from GitHub, fine for small orgs, slow for big ones). Only prompts when you're at an actual terminal -- in CI/scripts it just exits and tells you to set GITHUB_TOKEN.
A few tips
- Start with
--dry-runon any org you haven't scanned before, just to see the queue size before it touches trufflehog. --exclude-bot-loginsis basically free -- always worth passing onorg-membersmode.- Big org and rate limits hurting? Bump
--api-workersdown, not up, counterintuitively -- fewer parallel calls means fewer 403s to back off from. - Findings live in the cache even without
--save, so if you forgot the flag you can just re-run with it added -- nothing gets rescanned.
Resuming
Everything lands in ghscan_cache.sqlite3 (or wherever --db-path
points). Just re-run the same command and it'll pick up where it left
off -- already-discovered repos, contributors, and scan results are
never redone. Pass --fresh to wipe the cache and start over.
Repos that were already scanned in an earlier run also get automatically
checked for new pushes since their last scan (comparing the repo's
pushed_at against when the last scan finished) and get requeued if
they've changed. So re-running the same command a week later mostly just
scans what's new.
Output
By default the full report (summary + findings + skipped/failed repos)
just prints to your terminal at the end of the run -- nothing is written
to disk unless you pass --save:
ghscan --org some-org --save
ghscan --org some-org --save --report-json-path findings.json
All the flags
Filtering
--org <name>-- target org (required)--include-archived-- include archived repos (default: skipped)--include-forks-- include forked repos (default: skipped)--include-forks-if-ahead-- with--include-forks, only scan forks that actually have commits ahead of their upstream, instead of every fork (skips the huge number of forks that are byte-identical mirrors)--org-repos-only-- only scan the org's own repos; also skips the contributor-discovery API calls entirely, not just the final scan--contributor-repos-only-- only scan contributor-owned repos, skip the org's own repos--member-mode {contributors,org-members}--contributors(default) derives people from commit history across every org repo;org-membersuses the org's actual membership roster instead (tighter, but misses active outside contributors who aren't org members)--allow-private-- by default any repo the API returns marked private gets dropped as a safety guard; pass this to allow them through
Exclusions
--exclude-repo <owner/name>-- skip a specific repo, glob patterns allowed (e.g.--exclude-repo 'someupstream/*'), repeatable--exclude-login <login>-- never expand this contributor/member into their personal repos, repeatable--exclude-bot-logins-- auto-skip any login matching*[bot]--language <lang>-- only scan repos whose primary language matches (repeatable)--exclude-language <lang>-- skip repos whose primary language matches (repeatable)
Volume control
--max-contributor-repos <N>-- cap how many repos are pulled per contributor--min-stars <N>-- skip repos under this star count--max-repo-size-kb <N>-- skip repos bigger than this--pushed-within-days <N>-- skip repos with no push in the last N days--min-repo-age-days <N>-- skip repos created less than N days ago (throwaway/test repo filter, inverse of--pushed-within-days)--max-queue-size <N>-- hard cap on total repos scanned--sort-queue-by {pushed,stars,size}-- what order the queue is scanned in, and what--max-queue-sizekeeps first (default:pushed)
Concurrency
--api-workers <N>-- concurrent GitHub API discovery threads (default: 8)--scan-workers <N>-- concurrent TruffleHog processes (default: 3)
TruffleHog
--trufflehog-path <path>-- path to the binary (default:trufflehogonPATH)--trufflehog-timeout <seconds>-- per-repo timeout (default: 1800)--no-json-output-- don't append--json(findings won't be parsed into the report)--no-trufflehog-token-- don't passGITHUB_TOKENthrough to TruffleHog itself--trufflehog-arg <arg>-- pass an extra raw argument through, repeatable--shallow-depth <N>-- adds--depth=<N>to the TruffleHog call to limit how much history gets pulled on huge repos (trades scan speed for missing older secrets; only has an effect if your TruffleHog build honors--depth)
Persistence & output
--db-path <path>-- cache database location (default:ghscan_cache.sqlite3)--report-path <path>-- markdown report path, only written if--saveis also passed (default:ghscan_report.md)--report-json-path <path>-- optional JSON report path, same rule--save-- actually write the report file(s) to disk--fresh-- wipe the cache database and start over
Safety
--dry-run-- run discovery, print the estimated queue size and API call count, stop before scanning--yes-- skip the confirmation prompt that otherwise shows up before a wide-openorg-membersrun with no volume filters set
Logging
--log-level {DEBUG,INFO,WARNING,ERROR}--json-logs-- structured JSON log lines instead of plain text
Good faith
This scans personal repos belonging to real people, not just the org. Use it on orgs and accounts you own or have explicit permission to test. Don't run it against people who haven't agreed to it, and don't use whatever it finds for anything other than fixing the leak.
License
See LICENSE.md. Short version: free to use and modify for personal,
educational, and internal/authorized-testing purposes, but you can't
resell it, repackage it under another name, or strip the attribution.
Author
m4gester-bitt on github
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ghscan-1.1.3.tar.gz.
File metadata
- Download URL: ghscan-1.1.3.tar.gz
- Upload date:
- Size: 31.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f1422518352440144fb7dc46252fd7513534e9cdb5c6432d2f5ca0aa2267da6d
|
|
| MD5 |
a885375e8606b9c6f6e563e2c8843481
|
|
| BLAKE2b-256 |
4cbc2ae5d4a7335188d3fd483de1f5267fc8d600ece211f74d0be4e81b884b92
|
File details
Details for the file ghscan-1.1.3-py3-none-any.whl.
File metadata
- Download URL: ghscan-1.1.3-py3-none-any.whl
- Upload date:
- Size: 27.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e105eabedbcbc0ccbb488db9365d664b74f9395cc173bdaf885400be3d4dcd4a
|
|
| MD5 |
fb6bb9bb62860ef788b62c8f5bad9679
|
|
| BLAKE2b-256 |
249808da1ff7b5c24b62817e3c3d7cab9d149c4414599d45c8507994e14b4e4f
|