Skip to main content

js-secrets-extraction

Analyze JS bundles and source maps for hardcoded secrets, API keys, JWTs, and internal endpoints

소스 정보

저장소
uphiago/recon-skills
최근 소스 활동
2026년 7월 30일 00:23
감지된 SKILL.md 언어
영어
스타
1,306
포크
218

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
2 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
js-secrets-extraction
description
Analyze JS bundles and source maps for hardcoded secrets, API keys, JWTs, and internal endpoints
version
1.1.0
revision_date
2026-07-25T00:00:00.000Z
license
MIT
category
recon
tags
["js","secrets","API-key","jwt","source-map","recon"]
# JS Bundle & Source Map Analysis -- Secret Extraction ## When to Use - **ALWAYS** after initial web enumeration - When you find modern SPA (React, Angular, Vue) - When target uses Firebase, Supabase, Auth0 - Higher yield than directory scanning on many targets ## Why Analyze JS Bundles Modern JavaScript bundles (Webpack, Vite, esbuild) often contain: - Hardcoded API keys and tokens - Internal API URLs - Firebase, Auth0, Supabase configurations - Environment variables (VITE_*, REACT_APP_*, NEXT_PUBLIC_*) - Internal routes ## Bundle Download and Analysis ```bash curl --max-time 30 --connect-timeout 10 -s "https://target.com" > index.html grep -Eo 'src="[^"]*\.js"' index.html | cut -d'"' -f2 | while read js; do curl --max-time 30 --connect-timeout 10 -s "https://target.com$js" > "$(basename $js)" done # Search for secrets in bundles grep -rEn "(apiKey|api_key|API_KEY|token|secret|password|clientId|client_id|auth0|firebase|supabase)[\"'\"]?[[:space:]]*[:=][[:space:]]*[\"'\'][^\"'\']{8,}" *.js ``` ## Source Map Reconstruction ```bash curl --max-time 30 --connect-timeout 10 -sI "https://target.com/assets/index-abc123.js.map" curl --max-time 30 --connect-timeout 10 -sI "https://target.com/static/js/main.12345.js.map" # If HTTP 200, use for reconstruction: # https://unminify.com # https://source-map-visualization.netlify.app ``` **Real-world case**: Enterprise Angular SPA admin, 2 JS bundles (250KB each) exposed: - Internal API URL (apiv3.empresa.com.br) - Firebase API key (AIzaSy...2GXA) - Encryption keys (AD5oDjsJaTJOzLe1Llj9mz) - Cloudinary upload endpoint ## Port-Specific URL Analysis Modern deployments often serve the main SPA on port 443 and admin/API on separate ports (8080, 8081, 8084). **Always check JS bundles on ALL discovered ports:** ```bash # Check source maps on every open port for port in 443 8080 8081 8084; do curl --max-time 30 --connect-timeout 10 -sI "https://target.com:$port/static/js/main.*.js.map" 2>/dev/null curl --max-time 30 --connect-timeout 10 -sI "https://target.com:$port/assets/index-*.js.map" 2>/dev/null done ``` Source maps on administrative or alternate-port applications may expose a different route and configuration set from the public SPA. Analyze each authorized application independently. ## Admin Portal JS Analysis Pattern When you find an admin portal on a separate port, the JS bundle often contains different secrets than the main site: ```python base = "https://target.com:8080" # Admin portal js = requests.get(f"{base}/static/js/main.*.js").text # 1. Extract ALL API URLs api_urls = re.findall(r'https?://[^\"\'[[:space:]]\\n,)>\\]]+', js) # 2. Find base API URL (the backend this admin talks to) # 3. Look for hardcoded credentials, API keys, auth patterns # 4. Extract route paths for the admin app routes = re.findall(r'[\"\'](/[a-zA-Z0-9_/.-]*(?:admin|chat|bot|message|user|auth|login|token|config|setting|dashboard|hospital|pharmacy|drug|payment)[a-zA-Z0-9_/.-]*)[\"\']', js, re.IGNORECASE) ``` ## Source Map Content Analysis (1,200+ Files) When source maps are available, analyze the `sourcesContent` array for hardcoded secrets: ```python import json, re data = json.loads(open("bundle.js.map").read()) all_source = " ".join(data.get("sourcesContent", [])) # Search for credentials in the original source patterns = { "password": r'[\"\']([^\"\']*(?:password|passwd|pwd)[^\"\']*)[\"\']\s*[:=]\s*[\"\']([^\"\']+)[\"\']', "token": r'[\"\']([^\"\']*(?:token|jwt|api_key|apikey|secret)[^\"\']*)[\"\']\s*[:=]\s*[\"\']([^\"\']+)[\"\']', } for name, pat in patterns.items(): matches = re.findall(pat, all_source, re.IGNORECASE) if matches: print(f"[{name}] {matches[:5]}") ``` - Cloudinary upload endpoint ## Secret Regex Patterns Catalog ```python import re patterns = { "Firebase API Key": r'apiKey:\s*[\"\']([^\"\']{30,})', "AWS Key": r'(?:AKIA|ASIA)[A-Z0-9]{16}', "Google API Key": r'AIza[0-9A-Za-z\\-_]{35}', "JWT": r'eyJ[A-Za-z0-9_\\-]{20,}\.[A-Za-z0-9_\\-]{20,}\.[A-Za-z0-9_\\-]{10,}', "Mercado Pago": r'APP_USR-[a-f0-9]{8,}', "Stripe": r'(?:sk_live|pk_live)_[A-Za-z0-9]{24,}', "Auth0 Domain": r'(?:domain|auth0_domain):\s*[\"\']([^\"\']+\.auth0\.com)', "Auth0 Client ID": r'(?:client_id|clientId|AUTH0_CLIENT_ID):\s*[\"\']([^\"\']{20,})', "Supabase URL": r'(?:supabaseUrl|SUPABASE_URL):\s*[\"\'](https://[^\"\']+\.supabase\.co)', "Supabase Key": r'(?:supabaseKey|anonKey|SUPABASE_ANON_KEY):\s*[\"\'](eyJ[A-Za-z0-9_\\-]+\.[A-Za-z0-9_\\-]+\.[A-Za-z0-9_\\-]+)', "Heroku": r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}', "Generic Secret": r'(?:secret|password|token|key):\s*[\"\']([^\"\']{8,})', } ``` ## Batch Bundle Download + Grep ```python import requests, re, json base = "https://target.com" html = requests.get(base).text # Extract all JS URLs js_urls = re.findall(r'src="([^"]*\.js)"', html) for js_url in js_urls: if js_url.startswith("/"): js_url = base + js_url content = requests.get(js_url).text for name, pattern in patterns.items(): matches = re.findall(pattern, content) for m in matches: if isinstance(m, tuple): m = m[0] if len(m) > 6: print(f"[{name}] {m[:80]}") ``` ## Pitfalls | Issue | Solution | |-------|----------| | Bundles too large | Use grep -Eo with specific patterns | | Minified code (1 char names) | Use source maps for reconstruction | | False positive matches | Validate keys by testing API endpoint | | Rate limiting | Add delays between bundle downloads | --- ## Backend URL Discovery JS bundles frequently leak production backend URLs, enabling direct API attacks bypassing CDN/WAF: ```bash # Platform-specific backend URL patterns grep -Eo 'https?://[a-zA-Z0-9.\-]+\.(fly\.dev|azurewebsites\.net|onrender\.com|vercel\.app|netlify\.app)[^"'\'' ]{0,40}' /tmp/*.js grep -Eo 'https?://[a-zA-Z0-9.\-]+\.(supabase\.co|r2\.dev|blob\.vercel-storage\.com)[^"'\'' ]{0,40}' /tmp/*.js # Edge function URLs grep -Eo 'functions/v1/[a-zA-Z0-9_\-]+' /tmp/*.js # Internal API paths grep -Eo '["\x60]/api/v1/[a-zA-Z0-9_\-/]+["\x60]' /tmp/*.js ``` ### Real Field Patterns | Pattern | Platform | Example | Secret? | |---------|----------|---------|---------| | `*.fly.dev` | Fly.io | `ht-prod-backend.fly.dev` | ✅ Backend URL | | `*.azurewebsites.net` | Azure | `consigpro-api-prod-...` | ✅ Backend URL | | `*.onrender.com` | Render | `clickcity-api.onrender.com` | ✅ Backend URL | | `*.supabase.co` | Supabase | `jxhvjufqtabpeieyhkgk.supabase.co` | ✅ Anon key is public; backend URL is intel | | `*.r2.dev` | Cloudflare R2 | `pub-xxx.r2.dev` | ✅ Storage URL | | `functions/v1/*` | Supabase Edge | `provision-openrouter-key` | ✅ Endpoint name | | `dpl_*` | Vercel DPL | `dpl_BCoyPsxxYLZ...` | ❌ **NOT a secret** — public deploy ID | ## Verification ```bash # Test Firebase API key curl --max-time 30 --connect-timeout 10 -s "https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=AIza..." # Test Supabase anon key curl --max-time 30 --connect-timeout 10 -s "https://PROJECT.supabase.co/rest/v1/users?limit=1" -H "apikey: ANON_KEY" -H "Authorization: Bearer ANON_KEY" ``` ### Phase 5 — Source Map Exploitation Recover full pre-compiled source code when `.js.map` files are left in production: ```bash # Find .map files via Wayback Machine curl --max-time 30 --connect-timeout 10 -s "https://web.archive.org/cdx/search/cdx?url=*.target.com/*&collapse=urlkey&output=text&fl=original&filter=original:.*\.js\.map$" \ | sort -u > map_urls.txt # Download and extract source wget https://target.com/static/app.js.map node -e " const map = require('./app.js.map'); map.sources.forEach((src, i) => { const fs = require('fs'); fs.writeFileSync(src.split('/').pop(), map.sourcesContent[i]); }); print('Extracted ' + map.sources.length + ' source files'); " # Quick check: does a JS file have an available map? curl --max-time 30 --connect-timeout 10 -skI "https://target.com/static/app.js.map" | grep "200\|Content-Type"
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기