Skip to content

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:

text·output_sample.txt
[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 publicly

Architecture

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.

python·crawler.py
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)

python·ast_walker.py
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

bash·usage.sh
# 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.json

Results 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