#!/usr/bin/env python3 """KeyHunter v11 — Universal Secret Parser (consolidated from 9 catalogs). Features: - 180+ provider patterns (unified 160 + CN-ENV wave + SOTA) - Bracket-key extraction: [], {}, (), <> - Enrich output: provider, key, source, entropy, validation, masked, fingerprint, ts - Modular: --extract-only | --validate - 305+ ENV variable mappings - VALIDATION_META for 34 providers Canonical base: unified_key_patterns.py + src/key_patterns.py CN-wave + RESEARCH_upgrade.md + imba patterns_extra.py """ import argparse import base64 import hashlib import json import math import re import sys import time from collections import Counter # ═══════════════════════════════════════════════════════════════════════════════ # PATTERNS — canonical catalog (sorted: specific prefixes first, loose forms last) # ═══════════════════════════════════════════════════════════════════════════════ PATTERNS = [ # ── v6.5 gitleaks/trufflehog high-value rules ─────────────────────────── ('OPENAI_ADMIN', re.compile(r'\bsk-admin-[A-Za-z0-9_-]{58}T3BlbkFJ[A-Za-z0-9_-]{58}\b')), ('LANGSMITH', re.compile(r'\blsv2_(?:pt|sk)_[a-f0-9]{32}_[a-f0-9]{10}\b')), ('DATABRICKS', re.compile(r'\bdapi[a-f0-9]{32}(?:-\d)?\b')), ('DOPPLER', re.compile(r'\bdp\.pt\.[a-z0-9]{43}\b')), ('ARTIFACTORY', re.compile(r'\bAKCp[A-Za-z0-9]{69}\b')), ('ALIBABA_LTAI', re.compile(r'\bLTAI[a-z0-9]{12,22}\b')), ('AGE_KEY', re.compile(r'\bAGE-SECRET-KEY-1[QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7L]{58}\b')), ('ONEPASSWORD', re.compile(r'\bA3-[A-Z0-9]{6}-(?:[A-Z0-9]{11}|[A-Z0-9]{6}-[A-Z0-9]{5})-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}\b')), ('AZURE_AD', re.compile(r'\b[a-zA-Z0-9_~.]{3}\dQ~[a-zA-Z0-9_~.-]{31,34}\b')), # ── batch-2 (2026-10-06): HEROKU + SUPABASE ───────────────────────────── ('HEROKU', re.compile(r'\bHRKU-AA[0-9a-zA-Z_-]{58}')), ('SUPABASE', re.compile(r'\bsbp-[a-f0-9]{40}')), # ── AI inference providers (specific prefixes first) ──────────────────── ('ZAI', re.compile(r'[a-f0-9]{32}\.[A-Za-z0-9]{10,30}')), ('SAKANA', re.compile(r'fish_[a-f0-9]{64}')), ('OPENROUTER', re.compile(r'sk-or-v1-[0-9a-f]{48,70}')), ('DASHSCOPE', re.compile(r'sk-sp-[A-Za-z0-9_\-]{20,64}|sk-ws-[A-Za-z0-9_\-\.]{16,200}|sk-[a-f0-9]{32}(?![0-9a-fA-F])')), ('MINIMAX', re.compile(r'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9\.[A-Za-z0-9_\-]{20,}\.[A-Za-z0-9_\-]{20,}')), # NOTE: DEEPSEEK regex identical to DASHSCOPE alt — first-wins dedup ('DEEPSEEK', re.compile(r'sk-[a-f0-9]{32}')), ('SILICONFLOW', re.compile(r'sk-[a-zA-Z0-9]{48}')), ('KIMI', re.compile(r'sk-[A-Za-z0-9]{48}')), ('FAL', re.compile(r'\b[0-9a-f]{32}:[0-9a-f]{64}\b')), ('ARK', re.compile(r'(?:ARK|VOLCENGINE|DOUBAO|SEEDANCE|BYTEDANCE)_?API_KEY["\']?\s*[=:]\s*["\']?([A-Za-z0-9\-]{20,64})', re.IGNORECASE)), ('FIREWORKS', re.compile(r'(?:fireworks|FIREWORKS)[_a-z]{0,15}["\']?\s*[=:]\s*["\']?([A-Za-z0-9]{48,52})', re.IGNORECASE)), ('FIREWORKS', re.compile(r'fw_[A-Za-z0-9]{40,60}')), ('GROQ', re.compile(r'gsk_[A-Za-z0-9]{40,60}')), ('COHERE', re.compile(r'(?:cohere|COHERE)[_a-z]{0,15}["\']?\s*[=:]\s*["\']?([A-Za-z0-9]{40})', re.IGNORECASE)), ('NOVITA', re.compile(r'(?:novita|NOVITA)[_a-z]{0,15}["\']?\s*[=:]\s*["\']?([A-Za-z0-9_-]{32,40})', re.IGNORECASE)), ('PERPLEXITY', re.compile(r'pplx-[a-z0-9]{56}')), ('ELEVENLABS', re.compile(r'\b(?:elevenlabs|ELEVENLABS|xi)[_a-z]{0,15}["\']?\s*[=:]\s*["\']?([a-f0-9]{32})', re.IGNORECASE)), ('STABILITY', re.compile(r'sk-[A-Za-z0-9]{99}')), ('NVIDIA', re.compile(r'\bnvapi-[A-Za-z0-9_\-]{40,80}(?![A-Za-z0-9_\-])')), ('HUGGINGFACE', re.compile(r'hf_[A-Za-z0-9]{34,}')), ('GROK', re.compile(r'xai-[A-Za-z0-9_]{40,100}')), ('MESHY', re.compile(r'\bmsh_[A-Za-z0-9]{30,40}\b')), ('LUMA', re.compile(r'\bluma-[a-z0-9]{8}-[a-z0-9]{8}-[a-z0-9]{8}\b')), ('MISTRAL', re.compile(r'(?:mistral|MISTRAL)[_a-zA-Z]{0,15}["\']?\s*[=:]\s*["\']?([A-Za-z0-9]{32})(?![A-Za-z0-9])')), ('TOGETHER', re.compile(r'tgp_[A-Za-z0-9\-]{40,60}')), ('REPLICATE', re.compile(r'r8_[A-Za-z0-9]{37}')), ('CEREBRAS', re.compile(r'csk-[a-z0-9]{60}')), # ── SOTA — 2026-10-15 from RESEARCH_upgrade.md ────────────────────────── ('FEATHERLESS', re.compile(r'\bfea_[A-Za-z0-9]{30,}\b')), ('BROWSERBASE', re.compile(r'\bbbs_[A-Za-z0-9]{30,}\b')), ('MODAL_TOKEN', re.compile(r'\bAk-[A-Za-z0-9]{40}\b')), ('INFRACOST', re.compile(r'\bico-[a-zA-Z0-9]{32}\b')), ('HF_ORG', re.compile(r'\bapi_org_[A-Za-z0-9]{34}\b')), ('GITLAB_ROUTABLE', re.compile(r'\bglrt-[A-Za-z0-9_\-]{20,}\b')), # ── captcha solver providers ──────────────────────────────────────────── ('TWOCAPTCHA', re.compile(r'(?:2captcha|rucaptcha|twocaptcha|two_captcha)[_a-z]{0,15}["\']?\s*[=:]\s*["\']?([a-zA-Z0-9]{32})', re.IGNORECASE)), ('CAPSOLVER', re.compile(r'(?:capsolver|cap_solver)[_a-z]{0,15}["\']?\s*[=:]\s*["\']?(CAP-[A-Za-z0-9_-]{20,45})', re.IGNORECASE)), ('ANTICAPTCHA', re.compile(r'(?:anticaptcha|anti_captcha)[_a-z]{0,15}["\']?\s*[=:]\s*["\']?([a-f0-9]{32})', re.IGNORECASE)), ('CAPMONSTER', re.compile(r'(?:capmonster|cap_monster)[_a-z]{0,15}["\']?\s*[=:]\s*["\']?([a-f0-9]{32})', re.IGNORECASE)), ('EZSOLVER', re.compile(r'(?:ezsolver|ez_solver)[_a-z]{0,15}["\']?\s*[=:]\s*["\']?([a-zA-Z0-9]{32})', re.IGNORECASE)), ('NOPECHA', re.compile(r'(?:nopecha|nope_cha)[_a-z]{0,15}["\']?\s*[=:]\s*["\']?([a-zA-Z0-9_\-]{20,64})', re.IGNORECASE)), ('AZCAPTCHA', re.compile(r'(?:azcaptcha|az_captcha)[_a-z]{0,15}["\']?\s*[=:]\s*["\']?([a-zA-Z0-9]{32})', re.IGNORECASE)), ('YESSOLVER', re.compile(r'(?:yessolver|yes_solver)[_a-z]{0,15}["\']?\s*[=:]\s*["\']?([a-zA-Z0-9]{32,64})', re.IGNORECASE)), ('TWOCAPTCHA_URL', re.compile(r'2captcha\.com/in\.\w+\?key=([a-f0-9]{32})')), # ── relay/gateway base URLs (ONE_API/NEW_API/DIFY/FASTGPT/LOBECHAT/ # OPENWEBUI/OLLAMA). MUST precede PROXY_HTTP/HTTPS_AUTH: _dedup keeps the # first label per value and relay URLs almost always carry a port. ('ENDPOINT_CN', re.compile( r'(?:ONE[_\s-]?API|NEW[_\s-]?API|DIFY|FASTGPT|LOBECHAT|OPENWEBUI|OLLAMA)' r'[_\s]*(?:(?:URL|HOST|BASE|ENDPOINT|API|SERVER|ADDRESS|ADDR|PROXY|DOMAIN)[_\s]*){1,2}' r'\s*[=:]\s*["\']?(https?://[^\s"\']{10,200})', re.IGNORECASE)), # ── proxy providers ───────────────────────────────────────────────────── ('SOAX', re.compile(r'(?:soax|SOAX)[_a-z]{0,15}["\']?\s*[=:]\s*["\']?([A-Za-z0-9_-]{20,50})(?![A-Za-z0-9])')), ('PROXY_SOCKS5', re.compile(r'socks5://(?:[^:@]+:[^@]+@)?[^\s"\'<>]+:\d{2,5}')), ('PROXY_HTTP', re.compile(r'https?://(?:[^:@]+:[^@]+@)?[^\s"\'<>]+:\d{2,5}')), ('DAYTONA', re.compile(r'dtn_[a-f0-9]{64}')), ('WEBSHARE', re.compile(r'(?:webshare)[_a-z]{0,15}["\']?\s*[=:]\s*["\']?([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})', re.IGNORECASE)), ('IPROYAL', re.compile(r'(?:iproyal|ip_royal)[_a-z]{0,15}["\']?\s*[=:]\s*["\']?([a-zA-Z0-9_-]{20,50})', re.IGNORECASE)), ('BRIGHTDATA', re.compile(r'(?:brightdata|luminati|brd)[_a-z]{0,15}["\']?\s*[=:]\s*["\']?([a-f0-9]{32})', re.IGNORECASE)), # ── messaging / social ────────────────────────────────────────────────── ('TELEGRAM', re.compile(r'\b\d{8,10}:AA[A-Za-z0-9_\-]{33}\b')), ('DISCORD', re.compile(r'mfa\.[A-Za-z0-9_\-]{24,120}(?![A-Za-z0-9_-])')), ('DISCORD', re.compile(r'(?]{1,64}:[^\\s\\"\'@<>]{4,}@[^\\s\\"\'<>]+')), ('MYSQL_URI', re.compile('mysql://[^\\s\\"\'<>]{1,64}:[^\\s\\"\'@<>]{4,}@[^\\s\\"\'<>]+')), ('MONGO_URI', re.compile('mongodb(?:\\+srv)?://[^\\s\\"\'<>]{1,64}:[^\\s\\"\'@<>]{4,}@[^\\s\\"\'<>]+')), ('REDIS_URI', re.compile('rediss?://:[^\\s\\"\'@<>]{4,}@[^\\s\\"\'<>]+')), ('HTTPS_AUTH', re.compile('https://[^\\s\\"\'/:@<>]{1,64}:[^\\s\\"\'@/<>]{4,}@[^\\s\\"\'<>]+')), ('AZURE_STORAGE', re.compile(r'DefaultEndpointsProtocol=https;AccountName=[a-z0-9][a-z0-9-]{1,22}[a-z0-9];AccountKey=[A-Za-z0-9+/]{86}==')), # ── v6 full-stack wave ────────────────────────────────────────────────── ('NEON', re.compile(r'napi_[A-Za-z0-9]{30,60}')), ('DROPBOX', re.compile(r'sl\.[A-Za-z0-9_-]{100,150}')), ('TWITTER', re.compile(r'AAAAAAAAA[A-Za-z0-9%]{50,90}')), ('BREVO', re.compile(r'xkeysib-[A-Za-z0-9]{16,64}-[A-Za-z0-9]{16,64}')), ('RESEND', re.compile(r're_[A-Za-z0-9]{28,50}')), ('MAILGUN', re.compile(r'\bkey-[a-f0-9]{32}\b')), ('SHOPIFY', re.compile(r'shp(?:at|ca|ss|pa|ua)_[a-fA-F0-9]{32}')), ('SQUARE', re.compile(r'sq0atp-[A-Za-z0-9_-]{22,60}')), ('SQUARE_SECRET', re.compile(r'sq0csp-[A-Za-z0-9_-]{40,60}')), ('STRIPE_WEBHOOK', re.compile(r'whsec_[A-Za-z0-9]{32,64}')), ('STRIPE_RESTRICTED', re.compile(r'rk_live_[A-Za-z0-9]{24,99}')), ('DIGITALOCEAN', re.compile(r'do[po]_v1_[a-f0-9]{64}')), ('DOCKER', re.compile(r'dckr_pat_[A-Za-z0-9_-]{30,}')), ('KAKAO', re.compile(r'KakaoAK [0-9a-f]{32}')), ('RUBYGEMS_PAT', re.compile(r'rubygems_[A-Za-z0-9]{30,}')), ('SONARQUBE', re.compile(r'squ_[A-Za-z0-9]{40,}')), ('GRAFANA', re.compile(r'glc_[A-Za-z0-9_-]{40,}')), ('LANGSMITH', re.compile(r'lsv2_(?:pt|sk)_[A-Za-z0-9]{40,}')), ('TAVILY', re.compile(r'tvly-[A-Za-z0-9]{26,48}')), ('FIRECRAWL', re.compile(r'fc-[a-f0-9]{32}')), ('NETLIFY', re.compile(r'nfp_[A-Za-z0-9]{40,46}')), ('RENDER', re.compile(r'rnd_[A-Za-z0-9]{32,}')), ('MAPBOX_SECRET', re.compile(r'sk\.eyJ[A-Za-z0-9_\-]{50,}')), ('HUBSPOT', re.compile(r'pat-(?:na|eu)\d-[A-Za-z0-9]{30,}')), ('AIRTABLE', re.compile(r'pat[A-Za-z0-9]{8,20}\.[A-Za-z0-9]{40,}')), ('SENTRY_DSN', re.compile(r'https://[a-f0-9]{32}@[a-z0-9.-]*sentry\.io/\d+')), ('PRIVATE_KEY', re.compile(r'-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]{0,6000}?-----END [A-Z ]*PRIVATE KEY-----')), ('MAILCHIMP', re.compile(r'\b[a-f0-9]{32}-us\d{1,2}\b')), ('ACCTOKEN', re.compile(r'access_token\$production\$[a-z0-9]{16}\$[a-f0-9]{32}')), # ── v7 PatternForge wave ──────────────────────────────────────────────── ('JINA', re.compile(r'(?]*sig=[^\s"\'<>]+')), ('GITLAB_RUNNER', re.compile(r'\bGR1348941[A-Za-z0-9_\-]{20,}\b')), ('SOURCEGRAPH', re.compile(r'\bsgp_[a-f0-9]{40}\b')), ('APIFY', re.compile(r'\bapify_api_[A-Za-z0-9]{36}\b')), ] # ═══════════════════════════════════════════════════════════════════════════════ # ENV_VARS — 305+ environment → provider mappings # ═══════════════════════════════════════════════════════════════════════════════ _ENV_VARS = [ # core AI providers ('DEEPSEEK_REASONER_API_KEY', 'DEEPSEEK'), ('ALIYUN_DASHSCOPE_API_KEY', 'DASHSCOPE'), ('CLAUDE_CODE_ACCESS_TOKEN', 'ANTHROPIC_OAT'), ('STABLE_DIFFUSION_API_KEY', 'STABILITY'), ('CLAUDE_CODE_OAUTH_TOKEN', 'ANTHROPIC_OAT'), ('QWEN_DASHSCOPE_API_KEY', 'DASHSCOPE'), ('TONGYI_QIANWEN_API_KEY', 'DASHSCOPE'), ('DEEPSEEK_CODER_API_KEY', 'DEEPSEEK'), ('ALIBABA_CLOUD_API_KEY', 'DASHSCOPE'), ('DASHSCOPE_LLM_API_KEY', 'DASHSCOPE'), ('DEEPSEEK_ACCESS_TOKEN', 'DEEPSEEK'), ('DEEPSEEK_CHAT_API_KEY', 'DEEPSEEK'), ('ANTHROPIC_OAUTH_TOKEN', 'ANTHROPIC_OAT'), ('HUGGINGFACE_API_TOKEN', 'HUGGINGFACE'), ('ALIBABACLOUD_API_KEY', 'DASHSCOPE'), ('ALIYUN_CLOUD_API_KEY', 'DASHSCOPE'), ('ALIBABA_QWEN_API_KEY', 'DASHSCOPE'), ('DEEPSEEK_PRO_API_KEY', 'DEEPSEEK'), ('NVIDIA_BUILD_API_KEY', 'NVIDIA'), ('OPEN_ROUTER_API_KEY', 'OPENROUTER'), ('ALIBABA_LLM_API_KEY', 'DASHSCOPE'), ('DASHSCOPE_API_TOKEN', 'DASHSCOPE'), ('ALIYUN_QWEN_API_KEY', 'DASHSCOPE'), ('DEEPSEEK_API_SECRET', 'DEEPSEEK'), ('DEEPSEEK_V3_API_KEY', 'DEEPSEEK'), ('DEEPSEEK_V4_API_KEY', 'DEEPSEEK'), ('DEEPSEEK_R1_API_KEY', 'DEEPSEEK'), # short forms (widest coverage) ('OPENAI_API_KEY', 'OPENAI'), ('CLAUDE_API_KEY', 'ANTHROPIC'), ('GOOGLE_API_KEY', 'GOOGLE'), ('GEMINI_API_KEY', 'GOOGLE'), ('PERPLEXITY_KEY', 'PERPLEXITY'), ('NVIDIA_API_KEY', 'NVIDIA'), ('ZHIPU_API_KEY', 'ZAI'), ('DASHSCOPE_KEY', 'DASHSCOPE'), ('ANTHROPIC_KEY', 'ANTHROPIC'), ('MISTRAL_TOKEN', 'MISTRAL'), ('REPLICATE_KEY', 'REPLICATE'), ('FIREWORKS_KEY', 'FIREWORKS'), ('STABILITY_KEY', 'STABILITY'), ('Z_AI_API_KEY', 'ZAI'), ('GLM4_API_KEY', 'ZAI'), ('GLM5_API_KEY', 'ZAI'), ('BIGMODEL_KEY', 'ZAI'), ('KIMI_API_KEY', 'KIMI'), ('FUGU_API_KEY', 'SAKANA'), ('FISH_API_KEY', 'SAKANA'), ('QWEN_API_KEY', 'DASHSCOPE'), ('DEEPSEEK_KEY', 'DEEPSEEK'), ('2CAPTCHA_KEY', 'TWOCAPTCHA'), ('OPENAI_TOKEN', 'OPENAI'), ('TOGETHER_KEY', 'TOGETHER'), ('PPLX_API_KEY', 'PERPLEXITY'), ('HF_API_TOKEN', 'HUGGINGFACE'), ('ZAI_API_KEY', 'ZAI'), ('GLM_API_KEY', 'ZAI'), ('ZHIPUAI_KEY', 'ZAI'), ('CHATGLM_KEY', 'ZAI'), ('ALI_API_KEY', 'DASHSCOPE'), ('CAPTCHA_KEY', 'TWOCAPTCHA'), ('GCP_API_KEY', 'GOOGLE'), ('MISTRAL_KEY', 'MISTRAL'), ('NIM_API_KEY', 'NVIDIA'), ('SAKANA_KEY', 'SAKANA'), ('OR_API_KEY', 'OPENROUTER'), ('OPENROUTER', 'OPENROUTER'), ('QWEN_TOKEN', 'DASHSCOPE'), ('DS_API_KEY', 'DEEPSEEK'), ('OPENAI_KEY', 'OPENAI'), ('CLAUDE_KEY', 'ANTHROPIC'), ('NVIDIA_KEY', 'NVIDIA'), ('ZHIPU_KEY', 'ZAI'), ('Z_AI_KEY', 'ZAI'), ('OR_TOKEN', 'OPENROUTER'), ('QWEN_KEY', 'DASHSCOPE'), ('PPLX_KEY', 'PERPLEXITY'), ('HF_TOKEN', 'HUGGINGFACE'), ('ZAI_KEY', 'ZAI'), # medium forms ('TWO_CAPTCHA_API_KEY', 'TWOCAPTCHA'), ('TOGETHER_AI_API_KEY', 'TOGETHER'), ('REPLICATE_API_TOKEN', 'REPLICATE'), ('FIREWORKS_API_TOKEN', 'FIREWORKS'), ('OPENROUTER_API_KEY', 'OPENROUTER'), ('ALIYUN_LLM_API_KEY', 'DASHSCOPE'), ('TWOCAPTCHA_API_KEY', 'TWOCAPTCHA'), ('OPENAI_PROJECT_KEY', 'OPENAI'), ('CLAUDE_OAUTH_TOKEN', 'ANTHROPIC_OAT'), ('MISTRAL_AI_API_KEY', 'MISTRAL'), ('PERPLEXITY_API_KEY', 'PERPLEXITY'), ('SAKANA_AI_API_KEY', 'SAKANA'), ('DASHSCOPE_API_KEY', 'DASHSCOPE'), ('BAILIAN_API_TOKEN', 'DASHSCOPE'), ('RUCAPTCHA_API_KEY', 'TWOCAPTCHA'), ('OPENAI_SECRET_KEY', 'OPENAI'), ('ANTHROPIC_API_KEY', 'ANTHROPIC'), ('GOOGLE_AI_API_KEY', 'GOOGLE'), ('MISTRALAI_API_KEY', 'MISTRAL'), ('REPLICATE_API_KEY', 'REPLICATE'), ('FIREWORKS_API_KEY', 'FIREWORKS'), ('STABILITY_API_KEY', 'STABILITY'), ('HUGGINGFACE_TOKEN', 'HUGGINGFACE'), ('BIGMODEL_API_KEY', 'ZAI'), ('MOONSHOT_API_KEY', 'KIMI'), ('OPENROUTER_TOKEN', 'OPENROUTER'), ('ALICLOUD_API_KEY', 'DASHSCOPE'), ('MODELSCOPE_TOKEN', 'DASHSCOPE'), ('DEEPSEEK_API_KEY', 'DEEPSEEK'), ('2CAPTCHA_API_KEY', 'TWOCAPTCHA'), ('ANTHROPIC_APIKEY', 'ANTHROPIC'), ('GOOGLE_API_TOKEN', 'GOOGLE'), ('TOGETHER_API_KEY', 'TOGETHER'), ('PERPLEXITY_TOKEN', 'PERPLEXITY'), ('ZHIPUAI_API_KEY', 'ZAI'), ('CHATGLM_API_KEY', 'ZAI'), ('OPEN_ROUTER_KEY', 'OPENROUTER'), ('ALIBABA_API_KEY', 'DASHSCOPE'), ('DASHSCOPE_TOKEN', 'DASHSCOPE'), ('BAILIAN_API_KEY', 'DASHSCOPE'), ('QIANWEN_API_KEY', 'DASHSCOPE'), ('SEEDANCE_API_KEY', 'ARK'), ('ARK_API_KEY', 'ARK'), ('VOLCENGINE_API_KEY', 'ARK'), ('ARK_API_TOKEN', 'ARK'), ('DOUBAO_API_KEY', 'ARK'), ('BYTEDANCE_API_KEY', 'ARK'), ('FAL_KEY', 'FAL'), ('FAL_API_KEY', 'FAL'), ('FAL_AI_API_KEY', 'FAL'), ('QWEN2_5_API_KEY', 'DASHSCOPE'), ('DEEPSEEK_SECRET', 'DEEPSEEK'), ('CAPTCHA_API_KEY', 'TWOCAPTCHA'), ('TWO_CAPTCHA_KEY', 'TWOCAPTCHA'), ('ANTHROPIC_TOKEN', 'ANTHROPIC'), ('MISTRAL_API_KEY', 'MISTRAL'), ('TOGETHER_AI_KEY', 'TOGETHER'), ('REPLICATE_TOKEN', 'REPLICATE'), ('FIREWORKS_TOKEN', 'FIREWORKS'), ('STABILITY_TOKEN', 'STABILITY'), ('BIGMODEL_TOKEN', 'ZAI'), ('SAKANA_API_KEY', 'SAKANA'), ('OPENROUTER_KEY', 'OPENROUTER'), ('ALIYUN_API_KEY', 'DASHSCOPE'), ('TONGYI_API_KEY', 'DASHSCOPE'), ('DEEPSEEK_TOKEN', 'DEEPSEEK'), ('2CAPTCHA_TOKEN', 'TWOCAPTCHA'), ('HUGGINGFACEHUB_API_TOKEN', 'HUGGINGFACE'), ('FIREWORKS_AI_API_KEY', 'FIREWORKS'), ('NVIDIA_NIM_API_KEY', 'NVIDIA'), ('MINIMAX_API_KEY', 'MINIMAX'), ('GROQ_LLM_API_KEY', 'GROQ'), ('NOVITA_API_KEY', 'NOVITA'), ('COHERE_API_KEY', 'COHERE'), ('ELEVENLABS_API_KEY', 'ELEVENLABS'), ('GROQ_API_KEY', 'GROQ'), ('XI_API_KEY', 'ELEVENLABS'), ('XAI_API_KEY', 'GROK'), ('GROQ_TOKEN', 'GROQ'), ('NVIDIA_NIM', 'NVIDIA'), # captcha solvers ('CAPMONSTER_API_KEY', 'CAPMONSTER'), ('CAPMONSTER_KEY', 'CAPMONSTER'), ('EZSOLVER_API_KEY', 'EZSOLVER'), ('NOPECHA_API_KEY', 'NOPECHA'), ('AZCAPTCHA_API_KEY', 'AZCAPTCHA'), ('YESSOLVER_API_KEY', 'YESSOLVER'), # proxy ('SOAX_API_KEY', 'SOAX'), ('SOAX_TOKEN', 'SOAX'), ('WEBSHARE_API_KEY', 'WEBSHARE'), ('BRIGHTDATA_API_KEY', 'BRIGHTDATA'), ('DAYTONA_API_KEY', 'DAYTONA'), # traffic & infra ('AWS_ACCESS_KEY_ID', 'AWS'), ('AWS_SECRET_ACCESS_KEY', 'AWS'), ('AZURE_CLIENT_SECRET', 'AZURE'), ('CLOUDFLARE_API_TOKEN', 'CLOUDFLARE'), ('CF_API_TOKEN', 'CLOUDFLARE'), ('DIGITALOCEAN_TOKEN', 'DIGITALOCEAN'), ('DO_TOKEN', 'DIGITALOCEAN'), ('VULTR_API_KEY', 'VULTR'), ('LINODE_TOKEN', 'LINODE'), ('HEROKU_API_KEY', 'HEROKU'), ('VERCEL_TOKEN', 'VERCEL'), ('NETLIFY_AUTH_TOKEN', 'NETLIFY'), ('RUNPOD_API_KEY', 'RUNPOD'), ('MODAL_TOKEN', 'MODAL'), ('LAMBDA_API_KEY', 'LAMBDA'), ('PINECONE_API_KEY', 'PINECONE'), ('WEAVIATE_API_KEY', 'WEAVIATE'), ('QDRANT_API_KEY', 'QDRANT'), ('WANDB_API_KEY', 'WANDB'), ('LANGCHAIN_API_KEY', 'LANGCHAIN'), ('LANGSMITH_API_KEY', 'LANGCHAIN'), # messaging ('DISCORD_BOT_TOKEN', 'DISCORD'), ('DISCORD_TOKEN', 'DISCORD'), ('SLACK_BOT_TOKEN', 'SLACK'), ('NOTION_API_KEY', 'NOTION'), ('NOTION_TOKEN', 'NOTION'), ('SENDGRID_API_KEY', 'SENDGRID'), ('MAILGUN_API_KEY', 'MAILGUN'), ('TWILIO_AUTH_TOKEN', 'TWILIO'), ('STRIPE_SECRET_KEY', 'STRIPE'), # package registries ('NPM_TOKEN', 'NPM'), ('PYPI_TOKEN', 'PYPI'), ('GITHUB_TOKEN', 'GITHUB'), # generic ('JWT_SECRET', 'GENERIC_SECRET'), ('SESSION_SECRET', 'GENERIC_SECRET'), # v6 SaaS ('TAVILY_API_KEY', 'TAVILY'), ('FIRECRAWL_API_KEY', 'FIRECRAWL'), ('RESEND_API_KEY', 'RESEND'), ('BREVO_API_KEY', 'BREVO'), ('SENDINBLUE_API_KEY', 'BREVO'), ('SHOPIFY_ACCESS_TOKEN', 'SHOPIFY'), ('SHOPIFY_ADMIN_ACCESS_TOKEN', 'SHOPIFY'), ('SONAR_TOKEN', 'SONARQUBE'), ('SONARQUBE_TOKEN', 'SONARQUBE'), ('GRAFANA_TOKEN', 'GRAFANA'), ('GRAFANA_API_TOKEN', 'GRAFANA'), ('RUBYGEMS_AUTH_TOKEN', 'RUBYGEMS_PAT'), ('NEON_API_KEY', 'NEON'), ('TWITTER_BEARER_TOKEN', 'TWITTER'), ('MAPBOX_ACCESS_TOKEN', 'MAPBOX_SECRET'), ('MAPBOX_TOKEN', 'MAPBOX_SECRET'), ('DOCKER_HUB_TOKEN', 'DOCKER'), ('MAILCHIMP_API_KEY', 'MAILCHIMP'), ('MAILCHIMP_KEY', 'MAILCHIMP'), ('NETLIFY_TOKEN', 'NETLIFY'), # v7 PatternForge ('BASETEN_API_KEY', 'BASETEN'), ('DEEPINFRA_API_KEY', 'DEEPINFRA'), ('DEEPINFRA_TOKEN', 'DEEPINFRA'), ('MODAL_TOKEN_ID', 'MODAL'), ('MODAL_TOKEN_SECRET', 'MODAL'), ('FLY_API_TOKEN', 'FLYIO'), ('FLYIO_API_TOKEN', 'FLYIO'), ('SERPER_API_KEY', 'SERPER'), ('SERPAPI_API_KEY', 'SERPAPI'), ('SERPAPI_KEY', 'SERPAPI'), ('JINA_API_KEY', 'JINA'), ('VOYAGE_API_KEY', 'VOYAGE'), ('VOYAGEAI_API_KEY', 'VOYAGE'), ('BRAVE_SEARCH_API_KEY', 'BRAVE_SEARCH'), ('BRAVE_API_KEY', 'BRAVE_SEARCH'), ('EXA_API_KEY', 'EXA'), ('RUNWAYML_API_SECRET', 'RUNWAY'), ('RUNWAY_API_KEY', 'RUNWAY'), ('PIKA_API_KEY', 'PIKA'), ('SUNO_API_KEY', 'SUNO'), ('BFL_API_KEY', 'BFL'), ('BLACK_FOREST_LABS_API_KEY', 'BFL'), ('TENCENT_API_KEY', 'TENCENT'), ('HUNYUAN_API_KEY', 'TENCENT'), ('HUNYUAN_SECRET_ID', 'TENCENT'), ('HUNYUAN_SECRET_KEY', 'TENCENT'), ('SAMBANOVA_API_KEY', 'SAMBANOVA'), ('UPSTAGE_API_KEY', 'UPSTAGE'), ('LEPTON_API_TOKEN', 'LEPTON'), ('LEPTON_API_KEY', 'LEPTON'), ('NEARAI_API_KEY', 'NEARAI'), ('NEAR_AI_API_KEY', 'NEARAI'), ('LANGFUSE_PUBLIC_KEY', 'LANGFUSE'), ('LANGFUSE_SECRET_KEY', 'LANGFUSE'), ('LANGFUSE_API_KEY', 'LANGFUSE'), ('ALEPH_ALPHA_API_KEY', 'ALEPH_ALPHA'), ('AI21_API_KEY', 'AI21'), ('STEPIFUN_API_KEY', 'STEPFUN'), ('BAICHUAN_API_KEY', 'BAICHUAN'), ('ZEROONE_API_KEY', 'LEADERS'), ('LEADERS_API_KEY', 'LEADERS'), # ── CN-ENV wave (2026-10-11): Chinese AI providers & gateways ────────── ('BAIDU_API_KEY', 'BAIDU'), ('BAIDU_SECRET_KEY', 'BAIDU'), ('QIANFAN_AK', 'BAIDU'), ('QIANFAN_SK', 'BAIDU'), ('YI_API_KEY', 'YI'), ('01AI_API_KEY', 'YI'), ('STEPFUN_API_KEY', 'STEPFUN'), ('IFLYTEK_API_KEY', 'IFLYTEK'), ('IFLYTEK_API_SECRET', 'IFLYTEK'), ('IFLYTEK_APP_ID', 'IFLYTEK'), ('SPARK_API_KEY', 'IFLYTEK'), ('SPARK_API_SECRET', 'IFLYTEK'), ('ONEAPI_CHANNEL_KEY', 'ONEAPI'), ('NEWAPI_CHANNEL_KEY', 'ONEAPI'), ('ONE_API_KEY', 'ONEAPI'), ('DIFY_MODEL_KEY', 'DIFY'), ('DIFY_API_KEY', 'DIFY'), ('DIFY_OPENAI_KEY', 'DIFY'), ('FASTGPT_KEY', 'FASTGPT'), ('FASTGPT_API_KEY', 'FASTGPT'), ('LOBECHAT_OPENAI_KEY', 'LOBECHAT'), ('LOBECHAT_API_KEY', 'LOBECHAT'), ('OPENWEBUI_KEY', 'OPENWEBUI'), ('OPENWEBUI_API_KEY', 'OPENWEBUI'), ('MODELSCOPE_API_KEY', 'MODELSCOPE'), ('MODELSCOPE_ACCESS_TOKEN', 'MODELSCOPE'), ('OPENI_API_KEY', 'OPENI'), ('OPENI_ACCESS_TOKEN', 'OPENI'), ('MAXKB_API_KEY', 'MAXKB'), ('COZE_API_KEY', 'COZE'), ('COZE_BOT_KEY', 'COZE'), ('AGENTSCOPE_API_KEY', 'AGENTSCOPE'), ('AGENTSCOPE_MODEL_KEY', 'AGENTSCOPE'), ('METAGPT_API_KEY', 'METAGPT'), ('CHATGPT_NEXT_API_KEY', 'CHATNEXT'), ('CHATNEXT_API_KEY', 'CHATNEXT'), # ── unified-wave from goth-key-ripper ────────────────────────────────── ('PULUMI_ACCESS_TOKEN', 'PULUMI'), ('NEW_RELIC_API_KEY', 'NEWRELIC'), ('NEWRELIC_API_KEY', 'NEWRELIC'), ('NR_API_KEY', 'NEWRELIC'), ('GRAFANA_SERVICE_ACCOUNT_TOKEN', 'GRAFANA_SA'), ('GOOGLE_OAUTH_ACCESS_TOKEN', 'GOOGLE_CLOUD_OAUTH'), ('FIREBASE_SERVER_KEY', 'FIREBASE_SERVER'), ('TWILIO_ACCOUNT_SID', 'TWILIO_AC'), ('SALESFORCE_SESSION_ID', 'SALESFORCE'), ('SALESFORCE_SECRET', 'SALESFORCE'), ('COINBASE_API_KEY', 'COINBASE'), ('COINBASE_SECRET', 'COINBASE'), ('DISCORD_WEBHOOK_URL', 'DISCORD_WEBHOOK'), ('SLACK_WEBHOOK_URL', 'SLACK_WEBHOOK'), ('PAYPAL_ACCESS_TOKEN', 'PAYPAL'), ('DATADOG_API_KEY', 'DATADOG'), ('DATADOG_APP_KEY', 'DATADOG'), ('HUBSPOT_API_KEY', 'HUBSPOT'), ('INTERCOM_API_KEY', 'INTERCOM'), ('CONFLUENT_API_KEY', 'CONFLUENT'), ('CONFLUENT_CLOUD_API_KEY', 'CONFLUENT'), ('ELASTIC_API_KEY', 'ELASTIC_CLOUD'), ('ELASTIC_CLOUD_API_KEY', 'ELASTIC_CLOUD'), ('FASTLY_API_KEY', 'FASTLY'), ('LINODE_API_KEY', 'LINODE'), ('MONGODB_ATLAS_API_KEY', 'MONGODB_ATLAS'), ('OKTA_API_TOKEN', 'OKTA'), ('OKTA_CLIENT_TOKEN', 'OKTA'), # ── ApiScanExtract port (2026-10-19): env-context-gated, low-FP ── ('HEYGEN_API_KEY', 'HEYGEN'), ('APIFY_TOKEN', 'APIFY'), ('APIFY_API_TOKEN', 'APIFY'), ('SOURCEGRAPH_TOKEN', 'SOURCEGRAPH'), ('SRC_ACCESS_TOKEN', 'SOURCEGRAPH'), ('PROMPTLAYER_API_KEY', 'PROMPTLAYER'), ('WORDWARE_API_KEY', 'WORDWARE'), ('ASTRA_DB_APPLICATION_TOKEN', 'ASTRA'), ('ASTRA_TOKEN', 'ASTRA'), ('DEEPGRAM_API_KEY', 'DEEPGRAM'), ('ASSEMBLYAI_API_KEY', 'ASSEMBLYAI'), ('GLADIA_API_KEY', 'GLADIA'), ('LEONARDO_API_KEY', 'LEONARDO'), ('SYNTHESIA_API_KEY', 'SYNTHESIA'), ('CLIPDROP_API_KEY', 'CLIPDROP'), ('SCRAPINGBEE_API_KEY', 'SCRAPINGBEE'), ('ZENROWS_API_KEY', 'ZENROWS'), ('CREWAI_API_KEY', 'CREWAI'), ('COMPOSIO_API_KEY', 'COMPOSIO'), ('N8N_API_KEY', 'N8N'), ('FLOWISE_API_KEY', 'FLOWISE'), ('LANGFLOW_API_KEY', 'LANGFLOW'), ('GRETEL_API_KEY', 'GRETEL'), ('LABELBOX_API_KEY', 'LABELBOX'), ('MOSTLY_AI_API_KEY', 'MOSTLY_AI'), ('HELICONE_API_KEY', 'HELICONE'), ('BRAINTRUST_API_KEY', 'BRAINTRUST'), ('HUMANLOOP_API_KEY', 'HUMANLOOP'), ('REV_ACCESS_TOKEN', 'REV'), ('SPEECHMATICS_API_KEY', 'SPEECHMATICS'), ('UPSTASH_VECTOR_TOKEN', 'UPSTASH'), ('PORTKEY_API_KEY', 'PORTKEY'), ('LUMA_API_KEY', 'LUMA'), ] _VAR2PROV = dict(_ENV_VARS) _ALT = '|'.join(dict(_ENV_VARS)) ENV_RE = re.compile( '\\b(' + _ALT + ')\\b\\s*[=:,]\\s*[\'"]?([A-Za-z0-9_\\-.:$]{20,200})', re.IGNORECASE) # ═══════════════════════════════════════════════════════════════════════════════ # FILTERS — garbage / template / placeholder rejection # ═══════════════════════════════════════════════════════════════════════════════ GARBAGE = ("xxxx", "xxx", "your", "YOUR", "EXAMPLE", "example", "n0tr3al", "placeholder", "CHANGEME", "changeme", "dummy", "DUMMY", "abcdefghijklmnopqrst", "1234567890abcdef", "test-key", "sample", "SAMPLE", "insert", "replace", "aaaaaa", "redacted", "masked", "censored", "your_api_key", "replace_with", "fill_in", "undefined", "mock_", "stub_", "todo", "fixme", "paste", "none", "null", "apikey", "my_api_key", "fake_", "demo_", "test_key", "sk-xxx", "sk-your") _PLACEHOLDER_WORDS = ( 'your_', 'your-', 'xxxxx', 'placeholder', 'example', 'dummy', 'fake_', 'fake-', 'test_key', 'testkey', 'sample', 'demo_', 'replace', 'insert', 'paste', 'todo', 'changeme', 'change_me', 'put_here', 'add_here', 'fill_', 'enter_', 'set_', 'get_', 'api_key_here', '_here', 'key_here', 'token_here', 'none', 'null', 'undefined', 'secret_key', 'my_api_key', 'actualkey', 'apikey', 'sk-xxx', 'sk-your', 'xxxxxxxx') def _is_placeholder(val): """Check if value looks like a placeholder (x-heavy, low variety, etc.).""" low = val.lower() if any(w in low for w in _PLACEHOLDER_WORDS): return True if low.count('x') > len(val) * 0.4: return True if len(set(low)) <= 2: return True if val.isupper() and '_' in val and len(val) < 40: return True return False def _is_template(key): """Template junk that survives _is_junk — paired duplicates (aabbcc...) and monotone ramps (abcdef..., 12345678). Calibrated on 6000 real DB keys: 0 legit keys flagged.""" if len(key) > 160: return False body = key for pfx in ("sk-sp-", "sk-ws-", "sk-or-v1-", "sk-ant-api03-", "sk-", "pk-lf-", "sk-lf-", "csk-", "nvapi-", "r8_", "fish_"): if key.startswith(pfx): body = key[len(pfx):] break if len(body) < 8: return False if len(body) % 2 == 0 and all(body[i] == body[i + 1] for i in range(0, len(body), 2)): return True run = 1 for i in range(1, len(body)): if ord(body[i]) - ord(body[i - 1]) in (1, -1): run += 1 if run >= 20: return True else: run = 1 return False def _is_junk(key): """Reject placeholder/template keys (paired, ramps, repeats, stubs).""" if not key: return True if len(set(key)) < 4: return True if all(c in "_-.*xX0" for c in key): return True for blk in (2, 3, 4): if len(key) % blk == 0 and key[:blk] * (len(key) // blk) == key: return True if _is_template(key): return True low = key.lower() if "xxxx" in low or "yyyy" in low: return True if "insert_your" in low or "your_token" in low or "your_api_key" in low: return True if "placeholder" in low: return True if "<" in low and ">" in low: return True if "npm_" in low and low.count("x") > len(low) * 0.3: return True return False def _is_discord_jwt(t): """Discord bot token first segment = base64(numeric snowflake user id). Real tokens decode to 15-25 digits; random base64 blobs do not.""" head = t.split(".", 1)[0] try: d = base64.b64decode(head + "=" * (-len(head) % 4), validate=False) except Exception: return False return d.isdigit() and 15 <= len(d) <= 25 def _is_https_auth_junk(val): """HTTPS_AUTH anchoring — reject placeholder/doc URLs.""" if not val.startswith("https://"): return True rest = val[8:] if "@" not in rest: return True cred, _, host = rest.partition("@") user, _, pw = cred.partition(":") ul, pl = user.lower(), pw.lower() if "$" in cred or "{" in cred or "}" in cred or "<" in cred: return True PH_USER = {"admin", "user", "test", "root", "guest", "foo", "bar", "baz", "username", "login", "demo", "sample", "nobody", "user1"} PH_PW = {"admin", "password", "pass", "passwd", "secret", "test", "guest", "123456", "1234", "12345", "123", "changeme", "user", "root", "demo", "sample", "pwd", "hunter2", "letmein", "welcome", "qwerty", "abc123", "password1", "admin123", "token"} if ul in PH_USER and pl in PH_PW: return True if ul == pl and len(ul) < 24: return True if pl in PH_PW: return True hl = host.lower().split("/")[0].split(":")[0] if hl in ("localhost", "localhost.localdomain", "hostname", "your-host", "myserver", "server", "host", "foo.com", "bar.com", "baz.com"): return True if hl.endswith((".local", ".internal", ".invalid", ".test", ".localhost")): return True if hl.startswith(("127.", "10.", "192.168.", "0.")): return True if hl.startswith("172."): try: if 16 <= int(hl.split(".")[1]) <= 31: return True except (IndexError, ValueError): pass if hl in ("example.com", "example.org", "example.net") or hl.endswith( (".example.com", ".example.org", ".example.net")): return True if "." not in hl: return True return False def _is_pem_junk(val): """PRIVATE_KEY structural validation: body must base64-decode and carry plausible structure (openssh-key-v1 magic or ASN.1 SEQUENCE 0x30).""" head = val.split("-----")[1].upper() if val.count("-----") >= 2 else "" if "ENCRYPTED" in head: return True if "Proc-Type:" in val or "DEK-Info:" in val: return True try: body = val.split("-----", 2)[2] if val.count("-----") >= 2 else "" body = body.split("-----")[0] raw = base64.b64decode("".join(body.split()), validate=True) except Exception: return True if len(raw) < 24: return True if "OPENSSH" in val: return not raw.startswith(b"openssh-key-v1\x00") return raw[0] != 0x30 # ═══════════════════════════════════════════════════════════════════════════════ # BRACKET EXTRACTION — key between [], {}, (), <> # ═══════════════════════════════════════════════════════════════════════════════ BRACKET_RE = re.compile(r"""['"]([A-Za-z0-9/+=\.\-_]{20,300})['"]""") BARE_LINE_RE = re.compile(r'(?:^|\s)([A-Za-z0-9/+=_\-]{20,80})(?:\s|$)') _BRACKET_MAP = { '[': re.compile(r'\[([^\]]{20,300})\]'), '{': re.compile(r'\{([^\}]{20,300})\}'), '(': re.compile(r'\(([^\)]{20,300})\)'), '<': re.compile(r'<([^>]{20,300})>'), } def _scan_brackets(text): """Pre-scan for keys inside bracket pairs, then match against regex patterns. One pass through text, no overlap, dedup by key value.""" hits = [] seen = set() for br, rx in _BRACKET_MAP.items(): for m in rx.finditer(text or ""): inner = m.group(1) for prov, prx in PATTERNS: for km in prx.findall(inner): val = _flat(km) if len(val) >= 20 and val not in seen and not _is_junk(val): seen.add(val) hits.append((prov, val, m.start())) for m in BRACKET_RE.finditer(text or ""): inner = m.group(1) if inner in seen or len(inner) < 20: continue for prov, prx in PATTERNS: for km in prx.findall(inner): val = _flat(km) if len(val) >= 20 and val not in seen and not _is_junk(val): seen.add(val) hits.append((prov, val, m.start())) return hits def _entropy(data): """Shannon entropy in bits per character. Faster than Counter-based.""" if not data: return 0.0 n = len(data) freq = {} for b in data: freq[b] = freq.get(b, 0) + 1 return -sum((f / n) * math.log2(f / n) for f in freq.values()) def _fingerprint(key): """SHA-256 truncated to 8 hex chars for anonymous match-grouping.""" return hashlib.sha256(key.encode()).hexdigest()[:8] _MASK_RE = re.compile(r'^(.{4}).*(.{4})$') _MASK_TINY = re.compile(r'^(.{2})(.*)(.{2})$') def _mask(key): """Mask key: show first 4 and last 4 chars. Short keys show first/last 2.""" if len(key) <= 12: m = _MASK_TINY.match(key) if m: return m.group(1) + "*" * (len(key) - 4) + m.group(3) return "*" * len(key) m = _MASK_RE.match(key) if m: return m.group(1) + "*" * (len(key) - 8) + m.group(2) return "*" * len(key) # ═══════════════════════════════════════════════════════════════════════════════ # CORE SCANNER # ═══════════════════════════════════════════════════════════════════════════════ def _dedup(out): """Deduplicate and filter junk from (prov, key) list.""" seen_vals = set() res = [] for p, k in out: k = k.strip().strip("\"'`,;") if not k or len(k) < 20 or k in seen_vals: continue if any(g in k for g in GARBAGE) or _is_junk(k) or _is_placeholder(k): continue seen_vals.add(k) res.append((p, k)) return res def scan_text(text): """Yield (prov, key) from PATTERNS + ENV assignments + EXTRA + PHP.""" out = [] for prov, rx in PATTERNS: for m in rx.findall(text or ""): val = _flat(m) if prov == "DISCORD" and not val.startswith("mfa.") \ and not _is_discord_jwt(val): continue if prov == "HTTPS_AUTH" and _is_https_auth_junk(val): continue if prov == "PRIVATE_KEY" and _is_pem_junk(val): continue out.append((prov, val)) for m in ENV_RE.finditer(text or ""): out.append((_VAR2PROV.get(m.group(1).upper(), "ENV"), m.group(2))) _PHP_RE = re.compile( r"""define\s*\(\s*['"]([A-Za-z_][A-Za-z0-9_]*?)['"]\s*,\s*['"]([A-Za-z0-9_\-.:$]{20,200})['"]\s*\)""", re.IGNORECASE) for m in _PHP_RE.finditer(text or ""): out.append((_VAR2PROV.get(m.group(1).upper(), "ENV"), m.group(2))) for _name, _rx in EXTRA_PATTERNS.items(): try: for _m in _rx.findall(text or ""): out.append((str(_name).upper()[:32], _flat(_m))) except Exception: continue return _dedup(out) def scan_text_brackets(text): """Extended scan: bracket pre-scan + main scan, merged and deduped.""" main = scan_text(text) bracket = _scan_brackets(text) seen = {k for _, k in main} for prov, key, _pos in bracket: if key not in seen and not _is_junk(key): seen.add(key) main.append((prov, key)) return main # ═══════════════════════════════════════════════════════════════════════════════ # ENRICH — full structured output # ═══════════════════════════════════════════════════════════════════════════════ def enrich(provider, key): """Enrich a single hit with entropy, fingerprint, masked value, ts.""" return { "provider": provider, "key": key, "entropy": round(_entropy(key), 2), "masked": _mask(key), "fingerprint": _fingerprint(key), "len": len(key), "ts": int(time.time()), } def enrich_all(hits): return [enrich(prov, key) for prov, key in hits] # ═══════════════════════════════════════════════════════════════════════════════ # VALIDATION_META — live API validation endpoints (34 providers) # ═══════════════════════════════════════════════════════════════════════════════ VALIDATION_META = { 'OPENAI': {'endpoint': 'https://api.openai.com/v1/models', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'ANTHROPIC': {'endpoint': 'https://api.anthropic.com/v1/messages', 'headers': {'x-api-key': '{key}', 'anthropic-version': '2023-06-01'}, 'type': 'header'}, 'GITHUB_FINE': {'endpoint': 'https://api.github.com/user', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'GITLAB_PAT': {'endpoint': 'https://gitlab.com/api/v4/user', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'TWITTER': {'endpoint': 'https://api.twitter.com/2/users/me', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'SLACK_BOT': {'endpoint': 'https://slack.com/api/auth.test', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'TELEGRAM': {'endpoint': 'https://api.telegram.org/bot{key}/getMe', 'headers': {}, 'type': 'bearer'}, 'STRIPE': {'endpoint': 'https://api.stripe.com/v1/charges', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'SENDGRID': {'endpoint': 'https://api.sendgrid.com/v3/scopes', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'DIGITALOCEAN': {'endpoint': 'https://api.digitalocean.com/v2/account', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'CLOUDFLARE': {'endpoint': 'https://api.cloudflare.com/client/v4/user/tokens/verify', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'GOOGLE': {'endpoint': 'https://generativelanguage.googleapis.com/v1/models', 'headers': {'x-goog-api-key': '{key}'}, 'type': 'header'}, 'DROPBOX': {'endpoint': 'https://api.dropboxapi.com/2/users/get_current_account', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'NEWRELIC': {'endpoint': 'https://api.newrelic.com/v2/applications.json', 'headers': {'Api-Key': '{key}'}, 'type': 'header'}, 'PULUMI': {'endpoint': 'https://api.pulumi.com/api/user', 'headers': {'Authorization': 'token {key}'}, 'type': 'token'}, 'GRAFANA_SA': {'endpoint': 'https://grafana.com/api/org', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'GOOGLE_CLOUD_OAUTH': {'endpoint': 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={key}', 'headers': {}, 'type': 'url_param'}, 'FIREBASE_SERVER': {'endpoint': 'https://fcm.googleapis.com/fcm/send', 'headers': {'Authorization': 'key={key}'}, 'type': 'header'}, 'TWILIO_AC': {'endpoint': 'https://api.twilio.com/2010-04-01/Accounts/{key}.json', 'headers': {}, 'type': 'url_path'}, 'COINBASE': {'endpoint': 'https://api.coinbase.com/v2/user', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'DASHSCOPE': {'endpoint': 'https://dashscope.aliyuncs.com/api/v1/models', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'DEEPSEEK': {'endpoint': 'https://api.deepseek.com/v1/models', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'KIMI': {'endpoint': 'https://api.moonshot.cn/v1/models', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'ZAI': {'endpoint': 'https://open.bigmodel.cn/api/paas/v4/models', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'GROQ': {'endpoint': 'https://api.groq.com/openai/v1/models', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'PERPLEXITY': {'endpoint': 'https://api.perplexity.ai/models', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'HUGGINGFACE': {'endpoint': 'https://huggingface.co/api/whoami-v2', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'TOGETHER': {'endpoint': 'https://api.together.xyz/v1/models', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'REPLICATE': {'endpoint': 'https://api.replicate.com/v1/models', 'headers': {'Authorization': 'Token {key}'}, 'type': 'token'}, 'FIRECRAWL': {'endpoint': 'https://api.firecrawl.dev/v1/scrape', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'TAVILY': {'endpoint': 'https://api.tavily.com/search', 'headers': {}, 'type': 'url_param'}, 'HEROKU': {'endpoint': 'https://api.heroku.com/account', 'headers': {'Authorization': 'Bearer {key}', 'Accept': 'application/vnd.heroku+json; version=3'}, 'type': 'bearer'}, 'SUPABASE': {'endpoint': 'https://api.supabase.com/v1/projects', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, 'FEATHERLESS': {'endpoint': 'https://api.featherless.ai/v1/models', 'headers': {'Authorization': 'Bearer {key}'}, 'type': 'bearer'}, } # ═══════════════════════════════════════════════════════════════════════════════ # CLI # ═══════════════════════════════════════════════════════════════════════════════ def build_cli(): ap = argparse.ArgumentParser( description="KeyHunter v11 — Universal Secret Parser") ap.add_argument("files", nargs="*", help="Files to scan") ap.add_argument("--extract-only", action="store_true", help="Only extract flat (provider,key) pairs") ap.add_argument("--validate", action="store_true", help="Validate hits against live API endpoints") ap.add_argument("--brackets", action="store_true", help="Enable bracket pre-scan for embedded keys") ap.add_argument("-o", "--output", help="Output file (JSON)") ap.add_argument("--json", action="store_true", default=True, help="JSON output (default)") ap.add_argument("--quiet", "-q", action="store_true", help="Silence status output") return ap def main(): ap = build_cli() args = ap.parse_args() scanner = scan_text_brackets if args.brackets else scan_text all_hits = [] if not sys.stdin.isatty(): text = sys.stdin.read() all_hits.extend(scanner(text)) for fp in args.files: try: with open(fp, "r", encoding="utf-8", errors="replace") as fh: text = fh.read() except OSError as e: print(f"read {fp}: {e}", file=sys.stderr) continue all_hits.extend(scanner(text)) if not args.extract_only and not args.validate: enriched = enrich_all(all_hits) data = {"total": len(enriched), "hits": enriched} elif args.extract_only: data = {prov: key for prov, key in all_hits} else: data = {"total": len(all_hits), "hits": [{"provider": p, "key": k} for p, k in all_hits]} if args.output: with open(args.output, "w", encoding="utf-8") as fh: json.dump(data, fh, indent=2, ensure_ascii=False) if not args.quiet: print(f"Wrote {len(all_hits)} hits → {args.output}", file=sys.stderr) else: json.dump(data, sys.stdout, indent=2, ensure_ascii=False) sys.stdout.write("\n") def extract_all_keys(text): """[(provider, key)] — ENV context first (names trump patterns), then PATTERNS, KIMI pledge, and extra patterns.""" out = [] for m in ENV_RE.finditer(text or ""): out.append((_VAR2PROV.get(m.group(1).upper(), "ENV"), m.group(2))) for prov, rx in PATTERNS: for m in rx.findall(text or ""): out.append((prov, _flat(m))) for m in KIMI_PATTERN.finditer(text or ""): out.append(("KIMI", m.group(0))) for _name, _rx in EXTRA_PATTERNS.items(): try: for _m in _rx.findall(text or ""): out.append((str(_name).upper()[:32], _flat(_m))) except Exception: continue return _dedup(out) def _flat(m): """findall yields str, or tuple when the pattern has groups.""" if isinstance(m, (tuple, list)): for part in m: if isinstance(part, str) and len(part) >= 20: return part return "" return m # ═══════════════════════════════════════════════════════════════════════════════ # COMPAT LAYER — legacy key_patterns.py exports # ═══════════════════════════════════════════════════════════════════════════════ _by_prov = {} for _prov, _rx in PATTERNS: _by_prov.setdefault(_prov, []).append(_rx) def _merge_alts(rxs): parts = [] for rx in rxs: p = rx.pattern if rx.flags & re.IGNORECASE: p = "(?i:%s)" % p parts.append("(?:%s)" % p) return re.compile("|".join(parts)) KEY_PATTERNS = {p: (rs[0] if len(rs) == 1 else _merge_alts(rs)) for p, rs in _by_prov.items()} KIMI_PATTERN = re.compile(r'sk-[A-Za-z0-9]{48}') EXTRA_PATTERNS = {} try: from patterns_extra import EXTRA_PATTERNS as _EP EXTRA_PATTERNS = dict(_EP) except Exception: pass # ═══════════════════════════════════════════════════════════════════════════════ # SELF-CHECK # ═══════════════════════════════════════════════════════════════════════════════ if __name__ == "__main__": import hashlib as _hl def _body(seed, n, alpha="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"): """Deterministic pseudo-random body of length n using chars from alpha. Uses raw sha256 digest bytes (not hexdigest), so output is mixed-case with the full alpha range — avoids accidental 32-char lowercase-hex matches against ELEVENLABS/other patterns.""" out, i = "", 0 while len(out) < n: for b in _hl.sha256(f"{seed}:{i}".encode()).digest(): out += alpha[b % len(alpha)] if len(out) == n: return out i += 1 return out # Safe value for ENV context tests — survives all filters SV = _body("envsafe", 32) env_tests = [ ("DASHSCOPE_API_KEY", "DASHSCOPE"), ("MOONSHOT_API_KEY", "KIMI"), # uses sk- prefix via PATTERNS, ENV maps to KIMI ("ANTHROPIC_API_KEY", "ANTHROPIC"), ("2CAPTCHA_API_KEY", "TWOCAPTCHA"), ("SOAX_API_KEY", "SOAX"), ("OPENAI_API_KEY", "OPENAI"), ("GOOGLE_API_KEY", "GOOGLE"), ("AWS_ACCESS_KEY_ID", "AWS"), ("SLACK_BOT_TOKEN", "SLACK"), ("DISCORD_BOT_TOKEN", "DISCORD"), ("HEROKU_API_KEY", "HEROKU"), ("OPENROUTER", "OPENROUTER"), ("PERPLEXITY_API_KEY", "PERPLEXITY"), ("ZHIPUAI_API_KEY", "ZAI"), ] all_ok = True for env_name, expected in env_tests: text = f"{env_name}={SV}" hits = scan_text(text) providers = {p for p, _ in hits} if expected not in providers: print(f"FAIL ENV: expected {expected} for {env_name}, got {providers}") all_ok = False # ENDPOINT_CN regression guard: bare URL must NOT match cn_bare = scan_text("see https://api.openai.com/v1 in the docs") if [p for p, _ in cn_bare if p == "ENDPOINT_CN"]: print("FAIL ENDPOINT_CN: bare URL falsely matched") all_ok = False # Positive: ONE_API_URL=... must match cn_pos = scan_text("ONE_API_URL=http://gw.internal:3000/v1/chat") if not [p for p, _ in cn_pos if p == "ENDPOINT_CN"]: print("FAIL ENDPOINT_CN: ONE_API_URL missed") all_ok = False # Shared charsets for body generation HEX = "0123456789abcdef" ALNUM = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ALNUM_DASH = ALNUM + "_-" UPPER_DIGIT = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" DIGIT = "0123456789" LOWERALNUM = "0123456789abcdefghijklmnopqrstuvwxyz" # ── Direct prefix pattern matches ──────────────────────────────────────── # NOTE: KIMI regex (sk-[A-Za-z0-9]{48}) is identical to SILICONFLOW at line 52; # PATTERNS loop always claims sk-+48 matches for SILICONFLOW first. KIMI tested # via ENV (MOONSHOT_API_KEY → KIMI) above. direct_tests = [ ("OPENAI", f"sk-proj-{_body('openai', 80, ALNUM_DASH)}"), ("ANTHROPIC", f"sk-ant-api03-{_body('ant', 50, ALNUM_DASH)}"), ("OPENROUTER", f"sk-or-v1-{_body('or', 52, HEX)}"), ("GITHUB_PAT", f"ghp_{_body('ghp', 40, ALNUM)}"), ("SLACK_BOT", f"xoxb-{_body('sb1', 10, DIGIT)}" f"-{_body('sb2', 10, DIGIT)}" f"-{_body('sb3', 24, ALNUM)}"), ("AWS", f"AKIA{_body('aws', 16, UPPER_DIGIT)}"), ("GOOGLE", f"AIza{_body('goog', 35, ALNUM_DASH)}"), ("TELEGRAM", f"{_body('tg1', 10, DIGIT)}" f":AA{_body('tg2', 33, ALNUM_DASH)}"), ("SUPABASE", f"sbp-{_body('sbp', 40, HEX)}"), ("HEROKU", f"HRKU-AA{_body('hrku', 58, ALNUM_DASH)}"), ("PERPLEXITY", f"pplx-{_body('pplx', 56, LOWERALNUM)}"), ("ZAI", f"{_body('zai', 32, HEX)}.{_body('zai2', 12, ALNUM)}"), ("DISCORD", f"mfa.{_body('disc', 40, ALNUM_DASH)}"), ] for expected, text in direct_tests: hits = scan_text(text) providers = {p for p, _ in hits} if expected not in providers: print(f"FAIL DIRECT: expected {expected}, got {providers}") all_ok = False # Enrich smoke test (safe value, no GARBAGE substring) enriched = enrich_all([("OPENAI", _body("enrich", 40))]) assert len(enriched) == 1 assert enriched[0]["provider"] == "OPENAI" assert "fingerprint" in enriched[0] assert 0 < enriched[0]["entropy"] < 8 # Bracket extraction smoke test — use sk-or-v1- prefix so pattern matches bracket_body = f"sk-or-v1-{_body('bracket', 52, HEX)}" bracket_text = f'config: {{"api_key": "{bracket_body}"}}' bracket_hits = scan_text_brackets(bracket_text) assert any(p == "OPENROUTER" for p, _ in bracket_hits), \ f"bracket scan missed OPENROUTER: {bracket_hits}" # EXTRA_PATTERNS smoke test — gitlab session cookie (hex only) if EXTRA_PATTERNS: gl_body = _body("gl", 32, HEX) gl_text = f"_gitlab_session={gl_body}" gl_hits = scan_text(gl_text) gl_providers = {p for p, _ in gl_hits} if not gl_providers: print("FAIL EXTRA: _gitlab_session not detected by scan_text") all_ok = False else: print("WARN: patterns_extra.py not found — skipping EXTRA_PATTERNS test") total = len(env_tests) + len(direct_tests) if all_ok: print(f"SELF-CHECK PASS: {total}/{total}, enrich OK, brackets OK") else: print("SELF-CHECK FAIL") sys.exit(1) if len(sys.argv) > 1: main()