"""Shared key patterns — generated from eternal_v10 PROVIDERS registry (34 providers).""" import base64 import re PATTERNS = [ # v6.5 (2026-10-06): merged high-value rules from gitleaks v8 config and # trufflehog detectors (xai/openaiadmin/langsmith). Distinctive prefixes — # placed FIRST so first-wins dedup labels them before generic families. ('OPENAI_ADMIN', re.compile(r'\bsk-admin-[A-Za-z0-9_-]{58}T3BlbkFJ[A-Za-z0-9_-]{58}\b')), # XAI: covered by GROK above (xai- shape, registry knows GROK; a separate # XAI label would stall validation — one label per key shape). ('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 — anchored, unclaimed shapes, # allowlisted in eternal_v10 structural list (WORKING/unvalidated). # REJECTED: CLERK sk_(live|test)_ — shape owned by STRIPE (:80), second # label = mislabel race (one label per key shape doctrine). BAIDU # bce-v3/ALTAK-{id}/{sig} — per-request HMAC signature, not a credential. # heroku = gitleaks v2 форма (v1 uuid contextual — не flatten). ('HEROKU', re.compile(r'\bHRKU-AA[0-9a-zA-Z_-]{58}')), ('SUPABASE', re.compile(r'\bsbp-[a-f0-9]{40}')), ('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-[a-f0-9]{32}')), ('MINIMAX', re.compile(r'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9\.[A-Za-z0-9_\-]{20,}\.[A-Za-z0-9_\-]{20,}')), # NOTE: this regex is identical to DASHSCOPE's sk-<32hex> alternative above, # so DASHSCOPE always matches first and scan_text's value-dedup drops this # label for bare values. It is kept because _smoke_patterns.py requires # DEEPSEEK to be present in PATTERNS and other consumers filter on the label. # Mislabelling is fixed where it matters: validate_key writes the provider # that the live probe proved, not the one the regex guessed. ('DEEPSEEK', re.compile(r'sk-[a-f0-9]{32}')), ('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)), # URL-format captcha keys: 2captcha.com/in.php?key=... ('TWOCAPTCHA_URL', re.compile(r'2captcha\.com/in\.\w+\?key=([a-f0-9]{32})')), ('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)), ('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_-])')), # v7.1 bare revert (DEAD!=FP) ('OPENAI', re.compile(r'sk-proj-[A-Za-z0-9_-]{60,200}' r'|sk-svcacct-[A-Za-z0-9_-]{60,200}' r'|sk-None-[A-Za-z0-9_-]{20,200}' r'|"sk-[A-Za-z0-9]{20}iv|"sk-[A-Za-z0-9]{20}proj')), ('ANTHROPIC', re.compile(r'sk-ant-api03-[A-Za-z0-9_-]{20,120}')), ('ANTHROPIC_OAT', re.compile(r'sk-ant-oat01-(?=[A-Za-z0-9_-]{40,120}$)(?=[A-Za-z0-9_-]*\d)(?=[A-Za-z0-9_-]*[A-Z])[A-Za-z0-9_-]{40,120}')), ('GOOGLE', re.compile(r'(?:GOOGLE|google|GCP|gcp)[_ ]?(?:API|APPLICATION_CREDENTIALS|AI)[_ ]?(?:KEY|TOKEN|CREDENTIALS|FILE)?[\'"]?\s*[=:]\s*[\'"]?(AIza[A-Za-z0-9_-]{35})')), ('GOOGLE', re.compile(r'AIza[A-Za-z0-9_-]{35}')), # v7.1 bare restore (frontend ?key= / apiKey JSON) ('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}')), ('SILICONFLOW', re.compile(r'sk-[a-zA-Z0-9]{48}')), # v6.3: KIMI after SILICONFLOW so specific sk- formats win first ('KIMI', re.compile(r'sk-[A-Za-z0-9]{48}')), # v6.3: video-gen (Seedance 2.5 on Volcengine ARK + fal.ai) ('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'(?: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}')), ('ALIYUN', re.compile(r'LTAI[A-Za-z0-9]{12,20}')), # Measured against 275 nvapi- rows in data/keys.db: 263 real keys are # prefix+64 (70 total); the 4 run-ons are prefix+95..112. The old {80,120} # bound matched 0/263 real keys and 4/4 run-ons - it only ever caught junk. # Upper bound + negative lookahead stop greedy runs; \b alone does not. ('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}')), # v6.5: video-gen + zhipu bare ('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')), # v4 traffic & infra patterns ('AWS', re.compile(r'AKIA[A-Z0-9]{16}')), ('CLOUDFLARE', re.compile(r'(?:cf_|CF_)[A-Za-z0-9_-]{40,50}')), ('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 (2026-09-29): cloud/dev-tool/SaaS prefixes + PEM ('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: 2026-10-02 PatternForge wave — high-signal standalone prefixes ('JINA', re.compile(r'(? provider (from v10 registry vars) _ENV_VARS = [ ('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'), ('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'), ('MODELSCOPE_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'), ('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'), ('QWEN2_API_KEY', 'DASHSCOPE'), ('RUCAPTCHA_KEY', 'TWOCAPTCHA'), ('CAPTCHA_TOKEN', 'TWOCAPTCHA'), ('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'), ('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'), ('CAPMONSTER_API_KEY', 'CAPMONSTER'), ('CAPMONSTER_KEY', 'CAPMONSTER'), ('EZSOLVER_API_KEY', 'EZSOLVER'), ('NOPECHA_API_KEY', 'NOPECHA'), ('AZCAPTCHA_API_KEY', 'AZCAPTCHA'), ('YESSOLVER_API_KEY', 'YESSOLVER'), ('SOAX_API_KEY', 'SOAX'), ('SOAX_TOKEN', 'SOAX'), ('WEBSHARE_API_KEY', 'WEBSHARE'), ('BRIGHTDATA_API_KEY', 'BRIGHTDATA'), ('DAYTONA_API_KEY', 'DAYTONA'), # v4 traffic & infra ENV vars ('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'), ('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'), ('NPM_TOKEN', 'NPM'), ('PYPI_TOKEN', 'PYPI'), ('GITHUB_TOKEN', 'GITHUB'), ('JWT_SECRET', 'GENERIC_SECRET'), ('SESSION_SECRET', 'GENERIC_SECRET'), # v6 env vars: new SaaS/dev-tool providers ('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 env vars: 2026-10-02 PatternForge wave ('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'), ('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'), ('PINECONE_API_KEY', 'PINECONE'), ('UPSTAGE_API_KEY', 'UPSTAGE'), ('ALEPH_ALPHA_API_KEY', 'ALEPH_ALPHA'), ('AI21_API_KEY', 'AI21'), ('STEPIFUN_API_KEY', 'STEPIFUN'), ('BAICHUAN_API_KEY', 'BAICHUAN'), ('ZEROONE_API_KEY', 'LEADERS'), ('LEADERS_API_KEY', 'LEADERS'), ] _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) def _is_template(key): """v6.3: template junk that survives _is_junk — paired duplicates (aabbccddeeff…) and monotone ramps (abcdef…, 12345678). Calibrated on 6000 real DB keys: 0 legit keys flagged, 77 placeholders caught. Global Shannon entropy was rejected: sk-<32hex> tops out at 4 bits/char while some templates reach 5.0, so no threshold separates the classes.""" if len(key) > 160: return False # long blobs (JWTs etc) are not template material body = key for pfx in ("sk-sp-", "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 >= 8: return True else: run = 1 return False def _is_junk(key): """v6.4: 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 # v6.4: case-insensitive placeholder stubs 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 # v10.2: reject template interpolation placeholders like $$VARNAME:S$$ if "$$" in key: return True return False 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") def _is_discord_jwt(t): """Discord bot token first segment = base64(numeric snowflake user id). Gates the structurally loose [MN]... pattern: real tokens decode to 15-25 digits; random base64 blobs do not. Zero recall loss, kills blob FPs (which would otherwise become junk probes at Discord's API from the shared VPS IP).""" 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): """batch-3: HTTPS_AUTH anchoring — diff-probe of 68 targets found 0 real creds; mined corpus is mostly doc/placeholder URLs. Reject dead shapes at parse time: template interpolation, placeholder cred pairs, non-routable and documentation hosts.""" 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): """batch-3: PRIVATE_KEY structural validation, stdlib only (GCP-SA lesson: broken PEM fragments -> ValueError at probe time; openssh_key <0.0.6 has CVE-2022-31124 so no dep). Body must base64-decode and carry plausible structure: openssh-key-v1 magic for OPENSSH, ASN.1 SEQUENCE (0x30) for classic PEM types.""" head = val.split("-----")[1].upper() if val.count("-----") >= 2 else "" if "ENCRYPTED" in head: return True # encrypted PEM unusable without passphrase 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 def scan_text(text): """Yield (prov, key) from text via PATTERNS + ENV assignments.""" 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 # snowflake gate on the loose [MN] form if prov == "HTTPS_AUTH" and _is_https_auth_junk(val): continue # batch-3: placeholder/doc-shape anchoring if prov == "PRIVATE_KEY" and _is_pem_junk(val): continue # batch-3: structural base64/magic validation out.append((prov, val)) for m in ENV_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 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): continue seen_vals.add(k) res.append((p, k)) # first provider wins: PATTERNS is specific-first return res # ── compat layer ────────────────────────────────────────────────────────── # Legacy src/key_patterns.py exported KEY_PATTERNS / KIMI_PATTERN / ENV_RE / # extract_all_keys; root lanes import PATTERNS / scan_text. One file now serves # both so no module in either tree ImportErrors. def _flat(m): """findall yields str, or a 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 def _merge_alts(rxs): """One regex per provider: all its alternatives, flags preserved inline.""" 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)) _by_prov = {} for _prov, _rx in PATTERNS: _by_prov.setdefault(_prov, []).append(_rx) 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: EXTRA_PATTERNS = {} _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): 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 extract_all_keys(text): """[(provider, key)] via ENV context + prefix patterns + KIMI + mined. ENV_RE here is the 258-name table: group(1) = var name, group(2) = value. """ keys = [] seen = set() def add(prov, val): val = _flat(val) val = (val or "").strip().strip("\"'`,;") if len(val) < 20 or val in seen or _is_placeholder(val): return if any(g in val for g in GARBAGE) or _is_junk(val): return seen.add(val) keys.append((prov, val)) for m in ENV_RE.finditer(text or ""): add(_VAR2PROV.get(m.group(1).upper(), "ENV"), m.group(2)) for prov, rx in PATTERNS: for m in rx.findall(text or ""): add(prov, m) for m in KIMI_PATTERN.finditer(text or ""): add("KIMI", m.group(0)) for name, rx in EXTRA_PATTERNS.items(): try: for m in rx.findall(text or ""): add(str(name).upper()[:32], m) except Exception: continue return keys