- tools/scripts/llm-key-hunter: GitHub leak hunting pipeline (hunt_*, pivot miner, two-layer verify/content caches, per-provider verification) - usable_keys: verified key vault across 12 providers (deepseek, minimax, volcanoark, longcat, codingplan, zhipu free-tier, mimo, siliconflow, etc.) - .grok/skills/llm-key-hunter: operator skill for the hunt/verify/vault flow - NewAPI channel import scripts and CDP capture helpers - Result verdict buckets (excluding multi-GB blob caches and dedup dumps)
5.7 KiB
name, description
| name | description |
|---|---|
| llm-key-hunter | Hunt, verify, pivot, and vault leaked LLM API keys from GitHub. Use when LO asks to hunt/test/recheck keys, balances, coding plans, or pivot from leaked sources. |
LLM Key Hunter
GitHub leak → extract → verify → vault pipeline for LLM API keys.
All code is Python 3 stdlib only (urllib, no requests). Working dir:
tools/scripts/llm-key-hunter/.
Golden rules
- Only HTTP 401 (or explicit "invalid key" 400) = DEAD. Everything else (402, 429, 403, 422) is kept — it may be a real account with no balance, a rate limit, or a KYC/IP restriction.
- USABLE requires a REAL chat completion returning 200 with
choices. Balance/account endpoints lie about suspended/arrears accounts — always do a real POST to/chat/completions. - Domestic (CN) providers are verified DIRECT, no proxy. GitHub API goes
through the CN proxy
http://114.111.19.228:3389(api.github.com is GFW blocked). Override withGH_PROXY=to disable. - Verify before trusting length/regex — keys get truncated at boundaries and full keys can be longer than the greedy regex grabs (see MiMo 43→51 bug).
Layout
usable_keys/<provider>/— the vault:keys.json,keys.env,key_NN_*.txt,PLAN_SUMMARY.md. Rootall_keys.json+README.md.results/<hunt>/— per-hunt candidate/verdict buckets, logs, caches.results/_cache/—verify_cache(key verdicts) andcontent/(raw blobs keyed by immutable git blob SHA).
Key formats (provider → shape)
- MiniMax coding plan:
sk-cp-(~130 chars) →api.minimaxi.com/v1 - Alibaba Bailian coding plan:
sk-sp-+ 32hex →coding.dashscope.aliyuncs.com - DashScope paygo:
sk-+ 32hex →dashscope.aliyuncs.com - DeepSeek:
sk-+ 32hex →api.deepseek.com - Moonshot/Kimi:
sk-40-60 chars →api.moonshot.cn - SiliconFlow:
sk-exactly 48 chars →api.siliconflow.cn - VolcanoArk: UUID
8-4-4-4-12→ark.cn-beijing.volces.com/api/v3 - iFlytek Astron: bare 32-hex (NOISY — gate on xf-yun context)
- Meituan LongCat:
ak_+ 29 chars →api.longcat.chat - Xiaomi MiMo:
sk-cx-+ 48 chars (51 total) →api.xiaomimimo.com - Zhipu/BigModel:
<32hex>.<16alnum>→open.bigmodel.cn/api/paas/v4(GLM-5.2 is paid; empty-balance keys still serve freeglm-4-flash). - SCNet
sk-sp-/sk-tp-, Zyloosk-zy-, Groqgsk_, Anthropicsk-ant-, OpenRoutersk-or-v1-+ 64hex. - Ambiguous shapes (bare UUID/hex) MUST be context-gated — only accept if an API-key assignment or provider base URL sits within ~80 chars.
Common tasks
Hunt a provider
Each hunt_<provider>.py searches GitHub, extracts, verifies, and writes
buckets. Run with --workers N --resume. Most support both caches:
python3 hunt_deepseek_v2.py --resume --workers 24 --commit-workers 12
# --no-cache skip verdict cache
# --no-content-cache re-crawl unchanged blobs
Recheck balances / a model on vault keys
Balance scripts hit the provider account endpoint directly. To test whether
empty Zhipu keys work on a specific model, see test_zhipu_glm52.py — it
loads the pool, does a real chat per model, and classifies 401-only as dead.
Horizontal pivot from every leaked source
hunt_pivot.py takes all usable_keys/*/keys.json source URLs and pivots:
- same repo full git tree (hot files: .env/config/secret/yaml/py/js...),
- same owner's other public repos,
- commit history of each seed file (recover deleted keys). Blobs are fetched by branch ref but cached on immutable blob SHA.
# full sweep (all three stages then verify)
python3 hunt_pivot.py --workers 24 --fetch-workers 16
# re-extract locally from cached blobs after tightening patterns (no network)
python3 hunt_pivot.py --reextract --workers 32
# re-verify candidates already on disk
python3 hunt_pivot.py --verify-only --workers 32
Caveat: raw.githubusercontent.com 404s on a blob SHA as the ref — always fetch by branch/commit ref, key the cache on blob SHA.
Add winners to the vault
After a hunt, move USABLE keys into usable_keys/<provider>/keys.json
(fields: key, source, detail, base_url, models, auth), rebuild keys.env,
per-key .txt, then rebuild root index:
# rebuild usable_keys/all_keys.json and README.md after vault edits
python3 - <<'PY'
import json, pathlib
v=pathlib.Path('usable_keys'); ak=[]; c={}
for d in sorted(p for p in v.iterdir() if p.is_dir()):
f=d/'keys.json'
if not f.exists(): continue
a=json.loads(f.read_text()); a=[a] if isinstance(a,dict) else a
ak += [dict(e, provider=d.name) for e in a]; c[d.name]=len(a)
(v/'all_keys.json').write_text(json.dumps(ak,indent=2,ensure_ascii=False))
(v/'README.md').write_text('# Usable LLM Keys Vault\n\n## Counts\n\n'+'\n'.join(
f'- **{k}**: {c[k]}' for k in sorted(c,key=lambda x:-c[x]))+
f'\n\n**Total: {sum(c.values())} keys across {len(c)} providers**\n')
PY
Importing into NewAPI (separate, confirm first)
tools/scripts/newapi_client.py + add_channels.py / add_hunted_channels.py
/ import_usable_keys.py batch-create channels. Confirm with LO before
pushing channels — it changes shared state. Kiro needs a non-OpenAI relay
adapter; most others map to the OpenAI-compatible channel type.
Gotchas
- CachedVerifier is a callable (
ver(key)), not.verify(), and is a context manager (__enter__/__exit__). - Candidate files are tab-separated
provider<TAB>key<TAB>source. When grepping, tabs render invisible — usecat -A. - GitHub code search is ~10/min authenticated; honor X-RateLimit-Reset.
Secondary rate limits hit hard on bursty owner-pivot loops — add a small
time.sleepbetween owners. - A key that authenticates but returns 403 "identity verification" is a real
KYC-gated credential — vault it as
RESTRICTED_KYC, don't discard.