Fast GitHub API key leak scanner written in Rust. Find exposed API keys and help developers secure their secrets.
Find leaked API keys across all public GitHub repositories
Features • Quick Start • Docker • Verify • Providers • Config • Development
- 🚀 Blazing Fast: Parallel scanning with token rotation
- 🎯 45+ Providers: AI/LLM, Cloud, Payment, Database, and more
- 🔄 Rate Limit Bypass: Use multiple GitHub tokens for unlimited scanning
- 🔍 Smart Search: Finds keys in ANY file, not just .env
- ✅ Key Verification: Test if found keys are still active (20+ providers)
- 🎯 Verified-Only Mode: Use
-Vto scan+verify and output only active keys - 📊 Clean Output: Table, JSON, or CSV formats
- 💾 Auto-save: Results saved with timestamps
- ⏹️ Graceful Stop: Press Ctrl+C anytime to stop and save collected results
- 📝 Verbose Mode: See detailed logs of every file and URL being processed
- 🐳 Docker Ready: No Rust installation required - just use Docker
Most tools search for patterns like sk-proj- which appear in tutorials, docs, and examples. KeyHunter uses unique pattern segments that only exist in real keys:
| Provider | Others Search | KeyHunter Searches |
|---|---|---|
| OpenAI | sk-proj- |
T3BlbkFJ (unique Base64 in all keys) |
| Anthropic | sk-ant- |
sk-ant-api03- (real key prefix) |
| Stripe | sk_live_ |
sk_live_ + length validation |
For each provider, KeyHunter runs multiple searches:
- Pattern search - Unique identifier (
T3BlbkFJ) - Filename filter - Pattern +
filename:.env - Env var search -
OPENAI_API_KEY
This catches keys that single-pattern tools miss.
KeyHunter automatically skips placeholder keys:
sk-proj-xxxxxxxxxxxxxxxx ← skipped (placeholder)
sk-proj-YOUR_API_KEY_HERE ← skipped (example)
sk-proj-test_1234567890 ← skipped (test key)
sk-proj-T3BlbkFJx8Hn2m... ← ✓ real key
KeyHunter includes AI providers that most tools don't have yet:
| Category | Providers |
|---|---|
| AI / LLM | Anthropic, OpenAI, Google AI, Grok, DeepSeek, Groq, Perplexity, Replicate, HuggingFace, Fireworks, Cohere, Mistral, Together |
| New | Grok (xAI), DeepSeek, Groq, Perplexity |
| Tool Type | Purpose | Examples |
|---|---|---|
| Hunters (KeyHunter) | Find leaked keys across ALL public repos | Active scanning |
| Defenders | Scan YOUR repos to prevent leaks | TruffleHog, Gitleaks, git-secrets |
KeyHunter is built for security researchers who need to find exposed keys at scale.
Go to: https://github.com/settings/tokens/new
- Note:
keyhunter - Expiration: 30 days
- Scopes: ✅
public_repoonly
Click Generate token and copy it.
cp config.toml.example config.tomlEdit config.toml:
[github]
tokens = [
"ghp_YOUR_ACTUAL_TOKEN_HERE",
]cargo install github-keyhunter
# Run
keyhunter scan -p openai# Build (first time takes ~2 min)
cargo build --release
# Run
./target/release/keyhunter scan -p openai# Build image (~3-5 min first time)
docker build -t keyhunter .
# Run
docker run -v $(pwd)/config.toml:/app/config.toml \
-v $(pwd)/results:/app/results \
keyhunter scan -p openaiOption A: Two-step (recommended for large scans)
# Step 1: Scan for keys
./target/release/keyhunter scan -p openai
# Output: results/findings_20260119_143022.json
# Step 2: Verify which keys are active
./target/release/keyhunter verify -i results/findings_20260119_143022.json
# Output: results/verified_20260119_143100.json
# results/verified_20260119_143100_active.json (only active keys)Option B: One-step with -V (for smaller scans)
# Scan + verify in one command (verifies first 50 keys)
./target/release/keyhunter scan -p openai -V
# Output: results/verified_active_20260119_143022.json (only active keys)
# Or verify ALL found keys (caution: may hit rate limits)
./target/release/keyhunter scan -p openai -V --verify-allFull Docker documentation for those without Rust installed.
# 1. Setup config
cp config.toml.example config.toml
# Edit config.toml with your GitHub token
# 2. Build image (~3-5 min first time)
docker build -t keyhunter .
# 3. Run scan
docker run -v $(pwd)/config.toml:/app/config.toml \
-v $(pwd)/results:/app/results \
keyhunter scan -p openai
# With verbose mode
docker run -v $(pwd)/config.toml:/app/config.toml \
-v $(pwd)/results:/app/results \
keyhunter scan -p openai -v
# Show help
docker run keyhunter --help
# Show patterns
docker run keyhunter patternsSimpler syntax using docker-compose:
# Run with docker-compose
docker-compose run keyhunter scan -p openai
# With verbose
docker-compose run keyhunter scan -p openai -v
# Scan all providers
docker-compose run keyhunter scan
# Show patterns
docker-compose run keyhunter patterns| Command | Description |
|---|---|
docker build -t keyhunter . |
Build image |
docker run keyhunter --help |
Show help |
docker run keyhunter patterns |
List providers |
docker run -v ... keyhunter scan |
Run scan |
docker run -v ... keyhunter scan -V |
Scan + verify (active only) |
docker run -v ... keyhunter verify -i ... |
Verify keys |
docker-compose run keyhunter scan |
Run with compose |
| Mount | Purpose |
|---|---|
./config.toml:/app/config.toml |
Your config file |
./results:/app/results |
Save results locally |
Results are saved to your local ./results folder.
# Create alias for easier usage
alias keyhunter='docker run -v $(pwd)/config.toml:/app/config.toml -v $(pwd)/results:/app/results keyhunter'
# Then just run:
keyhunter scan -p openai
keyhunter scan -v
keyhunter patternskeyhunter <COMMAND>
COMMANDS:
scan Scan GitHub for leaked API keys
verify Verify if found keys are active
patterns Show all supported providers and patterns
help Show help for a command
Scan GitHub for leaked API keys.
Usage:
# Scan all providers
./target/release/keyhunter scan
# Scan specific provider
./target/release/keyhunter scan -p openai
./target/release/keyhunter scan -p anthropic
./target/release/keyhunter scan -p stripe_live
./target/release/keyhunter scan -p aws
# Verbose mode - see detailed logs
./target/release/keyhunter scan -v
./target/release/keyhunter scan -p openai -v
./target/release/keyhunter scan --verbose
# Custom search query (any GitHub code search)
./target/release/keyhunter scan -q "T3BlbkFJ"
./target/release/keyhunter scan -q "sk-ant-api03"
./target/release/keyhunter scan -q "OPENAI_API_KEY filename:.env"
./target/release/keyhunter scan -q "mongodb+srv:// filename:config.js"
# Different output formats
./target/release/keyhunter scan -o table # default, pretty
./target/release/keyhunter scan -o json # machine readable
./target/release/keyhunter scan -o csv # spreadsheet
# Use different config file
./target/release/keyhunter scan -c myconfig.toml
# Combine options
./target/release/keyhunter scan -p openai -o json -v
./target/release/keyhunter scan -p anthropic --verbose -c prod.toml
# Verified-only mode - only output active keys
./target/release/keyhunter scan -p openai -V
./target/release/keyhunter scan -p openai -V --verify-all
./target/release/keyhunter scan -p openai -V -o json
# Combine verbose + verified-only
./target/release/keyhunter scan -p openai -v -VOptions:
| Option | Description | Default |
|---|---|---|
-c, --config <FILE> |
Config file path | config.toml |
-p, --provider <n> |
Provider to scan | all |
-q, --query <QUERY> |
Custom GitHub search query | - |
-o, --output <FORMAT> |
Output: table, json, csv | table |
-v, --verbose |
Show detailed logs (files, URLs, etc.) | false |
-V, --verified-only |
Only save active (verified) keys | false |
--verify-all |
With -V: verify all keys (not just 50) | false |
-h, --help |
Show help | - |
Verified-Only Mode (-V):
Scan and verify in one command - only outputs keys that are confirmed active:
# Scan + verify first 50 keys, output only active
./target/release/keyhunter scan -p openai -V
# Scan + verify ALL keys (caution: may hit rate limits)
./target/release/keyhunter scan -p openai -V --verify-allNote: Without
-V, scan outputs all found keys (unverified). Useverifycommand later to check which are active.
Show all supported providers and their regex patterns.
Usage:
./target/release/keyhunter patternsOutput:
╭─────────────┬─────────────────────────┬─────────────────────╮
│ Provider │ Pattern │ Example │
├─────────────┼─────────────────────────┼─────────────────────┤
│ Anthropic │ sk-ant-api03-[...]{93} │ sk-ant-api03-xxxxx │
│ OpenAI │ sk-proj-[...]{48,180} │ sk-proj-xxxxx │
│ Google AI │ AIza[...]{35} │ AIzaSyDxxxxx │
│ AWS │ AKIA[0-9A-Z]{16} │ AKIAIOSFODNN7 │
│ Stripe │ sk_live_[...]{24,99} │ sk_live_xxxxx │
│ ... │ ... │ ... │
╰─────────────┴─────────────────────────┴─────────────────────╯
Verify if found keys are still active by testing against provider APIs.
Tip: For quick scans, use
scan -Vto scan+verify in one step. Use this separateverifycommand when you want more control over batch verification of large result files.
Usage:
# Verify first 50 keys (default, safe)
./target/release/keyhunter verify -i results/findings.json
# Verify only OpenAI keys
./target/release/keyhunter verify -i results/findings.json -p openai
# Verify first 100 keys
./target/release/keyhunter verify -i results/findings.json -l 100
# Verify ALL keys (careful - may hit rate limits)
./target/release/keyhunter verify -i results/findings.json -a
# More concurrent requests (faster but riskier)
./target/release/keyhunter verify -i results/findings.json -c 10
# Save to specific file
./target/release/keyhunter verify -i results/findings.json -o verified.jsonOptions:
| Option | Description | Default |
|---|---|---|
-i, --input <FILE> |
Results JSON file (required) | - |
-l, --limit <N> |
Verify first N keys | 50 |
-p, --provider <NAME> |
Verify only this provider | all |
-a, --all |
Verify all keys (ignore limit) | false |
-c, --concurrent <N> |
Parallel requests | 5 |
-o, --output <FILE> |
Save verified results | auto |
-h, --help |
Show help | - |
Output:
📂 Loaded 567 keys from results/findings.json
🔍 Verifying 50 keys with 5 concurrent requests
OpenAI 35 keys
Anthropic 10 keys
Stripe 5 keys
✓ ACTIVE sk-proj-...xxxx (OpenAI)
✓ ACTIVE sk-ant-a...yyyy (Anthropic)
════════════════════════════════════════════════════════════
✓ Verification Complete
🔴 12 keys are ACTIVE (leaked & working!)
🟢 35 keys are revoked/invalid
🟡 3 keys had errors (rate limited/timeout)
💾 Results saved to: results/verified_20260119.json
🔴 Active keys saved to: results/verified_20260119_active.json
Supported Verification:
| Provider | Method | Status |
|---|---|---|
| OpenAI | GET /v1/models | ✅ |
| Anthropic | POST /v1/messages | ✅ |
| Google AI | GET /v1/models | ✅ |
| Groq | GET /v1/models | ✅ |
| Perplexity | POST /chat/completions | ✅ |
| HuggingFace | GET /api/whoami-v2 | ✅ |
| Replicate | GET /v1/account | ✅ |
| Fireworks | GET /v1/models | ✅ |
| Cohere | GET /v1/models | ✅ |
| Mistral | GET /v1/models | ✅ |
| Together | GET /v1/models | ✅ |
| DeepSeek | GET /v1/models | ✅ |
| GitHub | GET /user | ✅ |
| GitLab | GET /api/v4/user | ✅ |
| Stripe | GET /v1/balance | ✅ |
| SendGrid | GET /v3/scopes | ✅ |
| Mailgun | GET /v3/domains | ✅ |
| Slack | GET /api/auth.test | ✅ |
| Discord | GET /users/@me | ✅ |
| Telegram | GET /getMe | ✅ |
| Mapbox | GET /tokens/v2 | ✅ |
| New Relic | GET /v2/users.json | ✅ |
| Datadog | GET /api/v1/validate | ✅ |
| AWS | ❌ | |
| Twilio | ❌ | |
| Firebase | ❌ |
Use these names with -p flag:
AI / LLM:
anthropic, openai, google, grok, deepseek, huggingface,
replicate, perplexity, groq, fireworks
Cloud:
aws
Payment:
stripe_live, stripe_restricted, paypal, square
Communication:
twilio, sendgrid, mailgun, mailchimp
Developer Platforms:
github_token, gitlab, npm, pypi
Social / Messaging:
slack_bot, slack_user, slack_webhook, discord,
discord_webhook, telegram
Database:
mongodb, postgres, mysql, redis
Other:
firebase, mapbox, sentry, newrelic, planetscale,
doppler, private_key
| Provider | Pattern | Search Term |
|---|---|---|
| Anthropic | sk-ant-api03-... |
sk-ant-api03- |
| OpenAI | sk-proj-... |
T3BlbkFJ |
| Google AI | AIza... |
AIzaSy |
| xAI Grok | xai-... |
xai- |
| DeepSeek | sk-[hex] |
DEEPSEEK_API_KEY |
| HuggingFace | hf_... |
hf_ |
| Replicate | r8_... |
r8_ |
| Perplexity | pplx-... |
pplx- |
| Groq | gsk_... |
gsk_ |
| Fireworks | fw_... |
fw_ |
| Provider | Pattern |
|---|---|
| AWS | AKIA... |
| Azure | ...(86 chars)== |
| Provider | Pattern |
|---|---|
| Stripe | sk_live_... |
| Square | sq0csp-... |
| PayPal | access_token$... |
| Provider | Pattern |
|---|---|
| Twilio | SK[hex]{32} |
| SendGrid | SG.... |
| Mailgun | key-... |
| Mailchimp | ...-us14 |
| Provider | Pattern |
|---|---|
| GitHub | ghp_..., github_pat_... |
| GitLab | glpat-... |
| NPM | npm_... |
| PyPI | pypi-... |
| Provider | Pattern |
|---|---|
| Slack Bot | xoxb-... |
| Slack User | xoxp-... |
| Slack Webhook | hooks.slack.com/... |
| Discord | Bot tokens |
| Discord Webhook | discord.com/api/webhooks/... |
| Telegram | 123456789:ABC... |
| Provider | Pattern |
|---|---|
| MongoDB | mongodb+srv://... |
| PostgreSQL | postgres://... |
| MySQL | mysql://... |
| Redis | redis://... |
| Provider | Pattern |
|---|---|
| Firebase | AAAA...:... |
| Mapbox | pk.eyJ... |
| Sentry | https://...@sentry.io |
| New Relic | NRAK-... |
| PlanetScale | pscale_tkn_... |
| Doppler | dp.pt.... |
| Private Key | -----BEGIN PRIVATE KEY----- |
🔍 Scanning 1 provider(s), 6 queries total
ℹ Press Ctrl+C to stop and save results
→ Provider: OpenAI (OpenAI API Key)
⟩ Query 1/6: T3BlbkFJ
⠙ [█████████▓░░░░░░░░░░░░░░░] 3/10 pages | 28 keys
↳ 282 keys found
⟩ Query 2/6: T3BlbkFJ filename:.env
↳ 285 keys found
✓ Running total: 567 unique keys
════════════════════════════════════════════════════════════════════════════════
🔑 Found 567 potential leaked keys
🔍 Scanning 1 provider(s), 6 queries total
ℹ Press Ctrl+C to stop and save results
→ Provider: OpenAI (OpenAI API Key)
⟩ Query 1/6: T3BlbkFJ
↳ 282 keys found
✓ Running total: 248 unique keys
🔍 Verifying keys...
🔍 Verifying 50 keys (--verified-only mode)
✓ ACTIVE sk-proj-SL...apsA (OpenAI)
✓ ACTIVE sk-proj-KK..._uIA (OpenAI)
════════════════════════════════════════════════════════════
🔑 Found 4 ACTIVE keys
💾 Active keys saved to: results/verified_active_20260119_143022.json
🔍 Scanning 1 provider(s), 6 queries total
ℹ Press Ctrl+C to stop and save results
📝 Verbose mode enabled - showing detailed logs
→ Provider: OpenAI (OpenAI API Key)
⟩ Query 1/6: T3BlbkFJ
· Page 1/10 - 30 files to process
✓ user/chatbot/.env → 2 key(s)
https://github.com/user/chatbot/blob/main/.env
✓ dev/project/config.js → 1 key(s)
https://github.com/dev/project/blob/main/config.js
· corp/docs/README.md → no keys
✓ startup/api/.env.local → 3 key(s)
https://github.com/startup/api/blob/main/.env.local
↳ Page 1 complete: 28 keys found
· Page 2/10 - 30 files to process
✓ another/repo/.env → 1 key(s)
https://github.com/another/repo/blob/main/.env
...
↳ 282 keys found
⟩ Query 2/6: T3BlbkFJ filename:.env
· Page 1/10 - 30 files to process
...
✓ Running total: 567 unique keys
════════════════════════════════════════════════════════════════════════════════
🔑 Found 567 potential leaked keys
Press Ctrl+C anytime during scanning to stop and save all collected results.
🔍 Scanning 1 provider(s), 6 queries total
ℹ Press Ctrl+C to stop and save results
→ Provider: OpenAI (OpenAI API Key)
⟩ Query 1/6: T3BlbkFJ
↳ 282 keys found
⟩ Query 2/6: T3BlbkFJ filename:.env
^C
⚠ Interrupted! Saving collected results...
💾 Saved 450 keys to: results/findings_20260119_143022_interrupted.json
Results are saved to *_interrupted.json so you don't lose your progress.
[github]
tokens = [
"ghp_YOUR_TOKEN_HERE",
]
concurrency = 5 # parallel requests
delay_ms = 500 # delay between requests
[scan]
max_results = 1000 # max results per query
[output]
format = "table" # table, json, csv (CLI -o overrides)
save_to_file = true
output_path = "results"
[providers]
openai = true
anthropic = true
aws = true
# ... see config.toml.example for all optionsControl how many results to fetch with max_results:
| max_results | Pages | Speed | Keys (approx) |
|---|---|---|---|
| 30 | ~1 | Fast test | ~50 |
| 100 | ~3 | Quick scan | ~150 |
| 300 | ~10 | Medium | ~500 |
| 500 | ~17 | Good coverage | ~1000 |
| 1000 | ~33 | Maximum | ~2000+ |
[scan]
max_results = 300 # adjust as needed| Setup | concurrency | delay_ms | Speed |
|---|---|---|---|
| Safe (1 token) | 3 | 1000 | ~30/min |
| Normal (1 token) | 5 | 500 | ~60/min |
| Fast (3+ tokens) | 10 | 300 | ~150/min |
| Blazing (5+ tokens) | 20 | 100 | ~300/min |
For maximum speed, use tokens from different GitHub accounts:
[github]
tokens = [
"ghp_from_account_1",
"ghp_from_account_2",
"ghp_from_account_3",
"ghp_from_account_4",
"ghp_from_account_5",
]
concurrency = 20
delay_ms = 100| Setup | Speed | Keys Found |
|---|---|---|
| 1 token, 1 account | 30/min | ~500/scan |
| 5 tokens, 5 accounts | 150/min | ~5000/scan |
| 10 tokens, 10 accounts | 300/min | ~10000/scan |
keyhunter/
├── Cargo.toml
├── config.toml.example
├── config.toml # Your config (git-ignored)
├── Dockerfile # Docker build
├── docker-compose.yml # Docker compose
├── .dockerignore
├── README.md
├── .gitignore
├── LICENSE
├── assets/
│ └── screenshot.png # Screenshot for README
├── results/ # Scan results saved here
├── src/
│ ├── main.rs # CLI entry point
│ ├── config.rs # Config parser
│ ├── patterns.rs # 45+ provider patterns
│ ├── github.rs # GitHub API client
│ ├── scanner.rs # Core scanner
│ └── verifier.rs # Key verification (20+ providers)
└── tests/
├── config_test.rs # Configuration tests
├── filters_test.rs # False positive filter tests
└── patterns_test.rs # Regex pattern tests
Option A: Native (Rust)
- Rust 1.70+ (
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh)
Option B: Docker
- Docker 20.10+
Native:
# Clone repository
git clone https://github.com/fadidevv/keyhunter.git
cd keyhunter
# Build debug (faster compile)
cargo build
# Build release (optimized)
cargo build --releaseDocker:
# Clone repository
git clone https://github.com/fadidevv/keyhunter.git
cd keyhunter
# Build image
docker build -t keyhunter .# Run all tests
cargo test
# Run specific test file
cargo test --test patterns_test
cargo test --test filters_test
cargo test --test config_test
# Run with output
cargo test -- --nocaptureTest Coverage:
patterns_test.rs- 34 tests for regex pattern matchingfilters_test.rs- 13 tests for false positive filteringconfig_test.rs- 12 tests for configuration parsing
# Format code
cargo fmt
# Run linter
cargo clippy
# Check without building
cargo checkNative:
# Setup config
cp config.toml.example config.toml
# Edit config.toml with your GitHub token
# Run debug build
cargo run -- scan -p openai
# Run release build
cargo run --release -- scan -p openaiDocker:
# Setup config
cp config.toml.example config.toml
# Edit config.toml with your GitHub token
# Run with Docker
docker run -v $(pwd)/config.toml:/app/config.toml \
-v $(pwd)/results:/app/results \
keyhunter scan -p openai- Add pattern to
src/patterns.rs:
KeyPattern {
name: "new_provider",
display_name: "New Provider",
regex: r"prefix_[a-zA-Z0-9]{32}",
confidence: "high",
search_terms: vec!["prefix_", "NEW_PROVIDER_KEY"],
example: "prefix_abc123...",
}- Add config toggle to
src/config.rs:
pub new_provider: bool,-
Add to
enabled_providers()insrc/config.rs -
(Optional) Add verification in
src/verifier.rs -
Run tests:
cargo test
This tool is for security research and educational purposes only.
- Only scan repositories you own or have permission to scan
- Report leaked keys responsibly to developers
- Never use found keys for unauthorized access
- Misuse may violate laws and GitHub Terms of Service
The authors are not responsible for misuse of this tool.
This tool is for:
- ✅ Security researchers finding and reporting leaked keys
- ✅ Developers scanning their own repositories
- ✅ Organizations auditing their code
- ✅ Helping developers secure their secrets
NOT for:
- ❌ Stealing or misusing credentials
- ❌ Unauthorized access to systems
- ❌ Any malicious purposes
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/new-provider) - Make your changes
- Run tests (
cargo test) - Run linter (
cargo clippy) - Format code (
cargo fmt) - Commit changes (
git commit -m 'Add new provider') - Push to branch (
git push origin feature/new-provider) - Open a Pull Request
Ideas for contributions:
- Add new API key providers
- Improve regex patterns
- Add verification for more providers
- Documentation improvements
- Bug fixes
MIT License - see LICENSE for details.
