Find secrets in a GitHub account's public repos — including the ones still hiding in git history after being 'deleted'.
Project description
gitghost
Finds secrets in a GitHub account's public repos — including the ones that got committed, then "deleted," but are still sitting in the git history where anyone can read them.
I built this after noticing how often the real leak isn't in someone's current code — it's in a commit from eight months ago that they thought they'd cleaned up. You paste an API key, catch it, delete the line, and move on. The latest version looks fine. But the old commit still has the key, and git log hands it to anyone who clones the repo. Most scanners only look at your current files and miss this entirely. gitghost goes digging through history for exactly those, and then rolls everything up into a single exposure score so you can actually tell how bad things are at a glance.
$ gitghost cy3erm
EXPOSURE SCORE: 96/100 [CRITICAL] grade F
· 7 live secrets in current code
· 3 "deleted" secrets still recoverable from history
· author email exposed in commit metadata
· timezone inferable from commit times (UTC+0530)
dossier written to gitghost-dossier.html
You get an HTML report you can open in a browser, not just a wall of terminal text. Every finding links straight to the spot — the exact file and line for live secrets, or the commit for the ones recovered from history — so you're not hunting for where the key actually is. And the report ends with a short how-to-fix guide, because the instinct when you see a leaked key (delete the file, nuke the repo) doesn't actually fix anything: the key's already been cloned. The real fix is to rotate it, then purge it from history, and the report walks you through both.
Running it
You'll need Python 3.10+ and git. There are no runtime dependencies — it's all standard library.
Install it as a command:
pipx install git+https://github.com/cy3erm/gitghost
gitghost <username>
Or just clone and run it without installing:
git clone https://github.com/cy3erm/gitghost
cd gitghost
python3 -m gitghost <username>
If you'd rather not point it at a real person first, there's a demo. It builds a little repo with fake credentials — including one that gets "deleted" a few commits in — so you can watch the history recovery dig it back out:
bash demo/make_demo_repo.sh /tmp/demo
python3 -m gitghost --local /tmp/demo --name demo
A few other flags:
python3 -m gitghost <username> --limit 50 # cap how many repos
python3 -m gitghost <username> --out report.html # where to write the report
python3 -m gitghost --local ./some-repo # scan a checkout you have locally
python3 -m gitghost --repo owner/name # scan just one repo (URL or owner/name)
Scanning more than a couple of accounts? Set GITHUB_TOKEN (any token works, it doesn't need any scopes) so you don't run into GitHub's 60-requests-an-hour limit for anonymous calls.
What it looks for
- Cloud and service keys — AWS, GCP, Stripe, GitHub, OpenAI, Slack, private keys, database URLs
- The same keys pulled back out of history after they were removed from the current code
- Metadata you might not realize you're sharing — the email in your commits, and a rough guess at your timezone and working hours from commit timestamps
- Committed
.envfiles, internal hostnames, hardcoded private IPs
The score is deliberately one number so you can watch it move — run it, clean things up, run it again. A single live cloud key is enough to put an account in the red by itself; a pile of smaller stuff pushes it up from there.
Where it draws the line
It only ever reads public repositories — things the account already chose to publish — and it's detection-only. It'll tell you a string looks like a credential and leave it at that. It won't try the key against the actual service to see if it still works, because quietly logging into someone else's account isn't the tool's job, and honestly it's not yours either. Findings in the report are shown as fingerprints, not the raw values, so you can share a report without leaking anything.
Point it at yourself first. Most people turn up at least one thing they'd completely forgotten about — I did. (The first time I pushed this repo, GitHub's own secret scanner blocked me because the demo's fake keys looked real enough to trip it. Which is about the best proof of the premise I could ask for.)
Adding your own detections
The patterns live in gitghost/rules.py. Each one is just a name, a regex, a severity, and a line of advice for fixing it — easy to add. If you write a good one, send a PR.
License
MIT
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 gitghost_scanner-1.2.0.tar.gz.
File metadata
- Download URL: gitghost_scanner-1.2.0.tar.gz
- Upload date:
- Size: 21.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
da4e5ef43488f251a5bdb3bd2b5dc6cf78feb60f5cf84524434570ee95a67401
|
|
| MD5 |
f1c5a44dfc01d34c1d13c6e350b4cf74
|
|
| BLAKE2b-256 |
f18de9d974bba80971e8106513649eb98ec1a7cd4b047bfb0ba01e8fa0b863a9
|
File details
Details for the file gitghost_scanner-1.2.0-py3-none-any.whl.
File metadata
- Download URL: gitghost_scanner-1.2.0-py3-none-any.whl
- Upload date:
- Size: 20.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eb63a7a4188684bacccdbd536ad1e5b7da5ada8ec0e6b5e1bd0acf087ca467bd
|
|
| MD5 |
8e32266858dc0e4c91129b0a3bf12fd5
|
|
| BLAKE2b-256 |
cb3bb935ee44eab258ea01afbb64114a335c7fe8f5d352e9a2fd32f2d510756a
|