Files
hack/tools/scripts/llm-key-hunter/verify.py
T
chaos 5d215e1649 Add LLM key-hunter toolkit, vault, and skill
- 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)
2026-08-02 06:02:58 +08:00

176 lines
7.3 KiB
Python

#!/usr/bin/env python3
"""Fast parallel LLM API key verifier — Python version.
Uses urllib instead of spawning curl subprocesses per key.
"""
import time
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor, as_completed
from collections import defaultdict
import urllib.request
import urllib.error
RESULTS_DIR = Path(__file__).parent / "results"
KEYS_FILE = RESULTS_DIR / "extracted_keys.txt"
LIVE_FILE = RESULTS_DIR / "live_keys_raw.txt"
# Provider verify configs
VERIFY_CONFIGS = {
"OpenAI": {"url": "https://api.openai.com/v1/models", "headers": {"Authorization": "Bearer {key}"}},
"Anthropic": {"url": "https://api.anthropic.com/v1/models", "headers": {"x-api-key": "{key}", "anthropic-version": "2023-06-01"}},
"Google": {"url": "https://generativelanguage.googleapis.com/v1/models?key={key}", "headers": {}},
"HuggingFace": {"url": "https://huggingface.co/api/whoami-v2", "headers": {"Authorization": "Bearer {key}"}},
"Groq": {"url": "https://api.groq.com/openai/v1/models", "headers": {"Authorization": "Bearer {key}"}},
"Replicate": {"url": "https://api.replicate.com/v1/account", "headers": {"Authorization": "Token {key}"}},
"TogetherAI": {"url": "https://api.together.xyz/models", "headers": {"Authorization": "Bearer {key}"}},
"DeepSeek": {"url": "https://api.deepseek.com/v1/models", "headers": {"Authorization": "Bearer {key}"}},
"OpenRouter": {"url": "https://openrouter.ai/api/v1/models", "headers": {"Authorization": "Bearer {key}"}},
"Perplexity": {"url": "https://api.perplexity.ai/chat/completions", "headers": {"Authorization": "Bearer {key}"}},
"VolcanoArk": {"url": "https://ark.cn-beijing.volces.com/api/v3/models", "headers": {"Authorization": "Bearer {key}"}},
"ZhipuAI": {"url": "https://open.bigmodel.cn/api/paas/v4/models", "headers": {"Authorization": "Bearer {key}"}},
"DashScope": {"url": "https://dashscope.aliyuncs.com/compatible-mode/v1/models", "headers": {"Authorization": "Bearer {key}"}},
"Moonshot": {"url": "https://api.moonshot.cn/v1/models", "headers": {"Authorization": "Bearer {key}"}},
"MiniMax": {"url": "https://api.minimaxi.com/v1/models", "headers": {"Authorization": "Bearer {key}"}},
"LingyiWanwu": {"url": "https://api.lingyiwanwu.com/v1/models", "headers": {"Authorization": "Bearer {key}"}},
"StepFun": {"url": "https://api.stepfun.com/v1/models", "headers": {"Authorization": "Bearer {key}"}},
"SiliconFlow": {"url": "https://api.siliconflow.cn/v1/models", "headers": {"Authorization": "Bearer {key}"}},
"LongCat": {"url": "https://api.longcat.chat/openai/models", "headers": {"Authorization": "Bearer {key}"}},
"OllamaCloud": {"url": "https://api.ollama.com/api/tags", "headers": {"Authorization": "Bearer {key}"}},
"FreeModel": {"url": "https://api.freemodel.dev/v1/models", "headers": {"Authorization": "Bearer {key}"}},
"XKiro": {"url": "https://api.xkiro.com/v1/models", "headers": {"Authorization": "Bearer {key}"}},
}
# Providers to skip (too many false positives, or no simple verify endpoint)
SKIP_PROVIDERS = {
"Mistral", "Cohere", "AzureOpenAI",
"iFlytekSpark", "iFlytekCodingPlan",
"TencentHunyuan",
"BaiduQianfan",
"CSDNCodingPlan", "HuaweiCodeArts", "MiMo", "InfiniAI", "JDCloud",
"MooreThreads", "Kuaishou", "UCloud", "Anomaly", "ChinaUnicom",
"SCNet", "AlibabaCodingPlan", "Zyloo",
}
def verify_key(provider, key):
"""Verify a key against its provider API. Returns True if live, False if dead, None if skipped."""
if provider in SKIP_PROVIDERS:
return None
if provider not in VERIFY_CONFIGS:
return None
cfg = VERIFY_CONFIGS[provider]
url = cfg["url"].replace("{key}", key)
headers = {hname: hval.replace("{key}", key) for hname, hval in cfg["headers"].items()}
req = urllib.request.Request(url, headers=headers, method="GET")
try:
with urllib.request.urlopen(req, timeout=10) as resp:
code = resp.getcode()
return code == 200 or (provider == "Perplexity" and code not in (401, 0))
except urllib.error.HTTPError as e:
code = e.code
if provider == "Perplexity":
return code not in (401, 0)
return code == 200
except Exception:
return False
def main():
# Read keys
keys = []
with open(KEYS_FILE) as f:
for line in f:
line = line.strip()
if not line:
continue
parts = line.split("|", 3)
if len(parts) >= 2:
provider = parts[0]
key = parts[1]
url = parts[2] if len(parts) > 2 else ""
desc = parts[3] if len(parts) > 3 else ""
keys.append((provider, key, url, desc))
print(f"Total keys: {len(keys)}")
# Group by provider and deduplicate
by_provider = defaultdict(dict) # provider -> {key: (url, desc)}
for provider, key, url, desc in keys:
if provider in SKIP_PROVIDERS:
continue
if provider not in VERIFY_CONFIGS:
continue
if key not in by_provider[provider]:
by_provider[provider][key] = (url, desc)
# Print summary
print("\nKeys by provider (deduplicated):")
total_to_verify = 0
for provider in sorted(by_provider.keys()):
n = len(by_provider[provider])
total_to_verify += n
print(f" {provider:20s}: {n:6d}")
print(f" {'TOTAL':20s}: {total_to_verify:6d}")
# Build verify list
to_verify = []
for provider, keydict in by_provider.items():
for key, (url, desc) in keydict.items():
to_verify.append((provider, key, url, desc))
# Verify in parallel
live_keys = []
dead_count = 0
processed = 0
start_time = time.time()
print(f"\nVerifying {len(to_verify)} keys with 30 threads...")
with ThreadPoolExecutor(max_workers=30) as pool:
futures = {pool.submit(verify_key, p, k): (p, k, u, d) for p, k, u, d in to_verify}
for future in as_completed(futures):
provider, key, url, desc = futures[future]
processed += 1
try:
result = future.result()
except Exception:
result = False
if result is True:
live_keys.append((provider, key, url, desc))
elif result is False:
dead_count += 1
if processed % 1000 == 0:
elapsed = time.time() - start_time
rate = processed / elapsed
print(f" [{processed}/{len(to_verify)}] live={len(live_keys)} dead={dead_count} ({rate:.0f}/s)")
elapsed = time.time() - start_time
print(f"\nDone in {elapsed:.1f}s: {len(live_keys)} live, {dead_count} dead")
# Write results
with open(LIVE_FILE, "w") as f:
for provider, key, url, desc in sorted(live_keys):
f.write(f"LIVE|{provider}|{key}|{url}|{desc}\n")
print(f"Live keys written to: {LIVE_FILE}")
# Print live keys by provider
live_by_provider = defaultdict(int)
for provider, key, url, desc in live_keys:
live_by_provider[provider] += 1
print("\nLive keys by provider:")
for provider in sorted(live_by_provider.keys()):
print(f" {provider:20s}: {live_by_provider[provider]}")
if __name__ == "__main__":
main()