Case Studies & ProjectsSecurity Researcher & Tool Author
NextScope — Building an Open-Source Frontend Vulnerability Scanner
By Burhan Moin
Background
Modern frontend frameworks — especially Next.js — leak a surprising amount of internal structure into the browser. API routes, server actions, internal fetch paths, and even database query parameters all end up in the client-side bundle if the developer is not careful. I found myself manually auditing these patterns on bug bounty targets and decided to automate it.
NextScope is the result: a Python CLI that crawls a target, extracts the full API surface from JS source, and produces a prioritised list of endpoints worth probing — with specific flags for common vulnerability classes.
What It Detects
The scanner flags several vulnerability classes in a single pass:
[IDOR] GET /api/users/[id] — user-controlled path param, no auth check visible
[OPEN] POST /api/admin/reset — no Authorization header in captured requests
[LEAK] GET /api/debug/config — returns server env vars in response (confirmed)
[PARAM] GET /api/search?q=&filter= — unvalidated params passed to DB query string
[SHADOW] POST /api/_next/data/... — internal Next.js data route exposed publiclyArchitecture
Phase 1 — Crawl
NextScope starts with a headless crawl of the target using the requests-html library (or optionally Playwright for JS-heavy SPAs). It follows all internal links up to a configurable depth and collects every JS bundle URL.
from urllib.parse import urljoin, urlparse
import requests
def crawl(base_url: str, depth: int = 3) -> list[str]:
visited, queue, scripts = set(), [base_url], []
session = requests.Session()
while queue and depth:
url = queue.pop(0)
if url in visited: continue
visited.add(url)
resp = session.get(url, timeout=10)
# extract <script src> and inline JS
scripts.extend(extract_scripts(resp.text, base_url))
queue.extend(extract_links(resp.text, base_url, visited))
depth -= 1
return list(set(scripts))Phase 2 — AST analysis
Each collected JS bundle is parsed into an AST using esprima (via a Python subprocess) or pyjsparser. The AST walker looks for:
• fetch() / axios calls with string or template-literal URLs
• Next.js router.push() / router.replace() with dynamic segments
• Direct XMLHttpRequest constructions
• next/server handler exports (indicating an API route file)
import re
# Fast regex pass before full AST parse (catches ~80% of endpoints)
PATTERNS = [
r'fetch(["']([/][^"']+)["']',
r'axios.[a-z]+(["']([/][^"']+)["']',
r'router.push(["']([/][^"']+)["']',
r'["'](/api/[^"'?s]+)',
]
def extract_endpoints(js_source: str) -> list[str]:
endpoints = []
for pattern in PATTERNS:
endpoints.extend(re.findall(pattern, js_source))
return list(set(endpoints))Phase 3 — Vulnerability classification
Extracted endpoints are run through a classifier that looks for IDOR patterns (path params that look like IDs), admin paths, debug/internal paths, and unauthenticated request patterns from the crawl traffic.
Usage
# Install
pip install nextscope # or: git clone + pip install -e .
# Basic scan
nextscope scan https://target.com
# Deep scan with Playwright (JS-heavy SPAs)
nextscope scan https://target.com --mode playwright --depth 5 --output report.jsonResults on Real Targets
I used NextScope during several bug bounty engagements and in personal research. Notable finds:
• A Next.js SaaS app exposing /api/admin/users without authentication — full user enumeration
• An e-commerce platform leaking internal product pricing logic through a /api/_next/data/ shadow route
• A job board with IDOR on /api/applications/[id] — could read any applicant's private CV
[ GitHub activity screenshots and example scan output to be added here ]
Source
NextScope is open source: github.com/burhanmoin1/nextscope