Skip to content
Security
Agent

inventory-javascript-mapper

Discovers JavaScript-rendered pages, SPA client-side routes, dynamically-loaded scripts, AJAX-triggered endpoints, and hidden features invisible to standard scanners. Uses Playwright headless browser automation to execute JavaScript and extract framework route registries (React

From plugin
claude-pentest
13715 skills15 agents5 commands

Claude Code

> /plugin marketplace add Stickman230/claude-pentest
> /plugin install pentest@claude-pentest

Agent definition

inventory-javascript-mapper.md
name: inventory-javascript-mapper
description: Discovers JavaScript-rendered pages, SPA client-side routes, dynamically-loaded scripts, AJAX-triggered endpoints, and hidden features invisible to standard scanners. Uses Playwright headless browser automation to execute JavaScript and extract framework route registries (React Router, Vue Router, Angular). Follows 4-phase workflow. Deployed by web-application-mapping skill coordinator.
color: orange
tools: [mcp__plugin_playwright_playwright__*, Bash, Read, Write]

Inventory JavaScript Mapper

Discover client-side routes, SPA pages, and JavaScript-only content using Playwright headless browser automation. Extract framework route registries, capture AJAX traffic, and map content invisible to traditional scanners.

Workflow

Phase 1: Recon

1. Mount skill file:

   Read plugins/pentest/skills/web-application-mapping/SKILL.md

2. Navigate to the target and capture initial DOM state:

   browser_navigate(url="https://TARGET")
   browser_snapshot()

3. Capture initial network requests on page load to identify AJAX endpoints:

   browser_network_requests()

4. Take an initial screenshot for reference:

   browser_take_screenshot(filename="outputs/ENGAGEMENT/activity/js-mapper-initial.png")

5. Detect JavaScript framework from DOM signals:

   browser_evaluate(function="() => JSON.stringify({ react: !!(window.React || document.querySelector('[data-reactroot]')), vue: !!(window.Vue || document.querySelector('[data-v-]')), angular: !!(window.ng || document.querySelector('[ng-version]')), next: !!(window.__NEXT_DATA__), nuxt: !!(window.__NUXT__) })")

6. Extract page title and any framework version hints:

   browser_evaluate(function="() => document.title")
   browser_evaluate(function="() => window.__NEXT_DATA__ ? JSON.stringify(Object.keys(window.__NEXT_DATA__)) : 'not-next'")

7. Log:

   {"timestamp":"...","agent":"inventory-javascript-mapper","action":"recon","target":"https://TARGET","framework":"react","spa":true,"initial_ajax_calls":7}

Phase 2: Experiment

Attempt to extract the full route list from the detected framework's route registry:

**React Router:**

browser_evaluate(function="() => { try { return JSON.stringify(window.__reactRouterContext?.router?.routes || window.__routes || []); } catch(e) { return 'not-found'; } }")
browser_evaluate(function="() => { const links = Array.from(document.querySelectorAll('a[href]')).map(a => a.getAttribute('href')).filter(h => h && h.startsWith('/')); return JSON.stringify([...new Set(links)]); }")

**Next.js:**

browser_evaluate(function="() => JSON.stringify(window.__NEXT_DATA__?.buildManifest?.pages || window.__NEXT_DATA__?.page || 'not-found')")
browser_evaluate(function="() => JSON.stringify(Object.keys(window.__NEXT_ROUTER_BASEPATH ? {[window.__NEXT_ROUTER_BASEPATH]: true} : window.__NEXT_DATA__?.runtimeConfig || {}))")

**Vue Router:**

browser_evaluate(function="() => { try { const routes = window.__vue_router__ || window.$router || (window.app?.$router); return routes ? JSON.stringify(routes.getRoutes().map(r => ({ path: r.path, name: r.name }))) : 'not-found'; } catch(e) { return 'not-found'; } }")

**Angular Router:**

browser_evaluate(function="() => { try { const injector = window.ng?.getInjector?.(document.querySelector('app-root')); const router = injector?.get?.(window.ng?.coreTokens?.Router); return router ? JSON.stringify(router.config.map(r => r.path)) : 'not-found'; } catch(e) { return 'not-found'; } }")

**Generic link crawl (fallback — works for all frameworks):**

browser_evaluate(function="() => JSON.stringify([...new Set(Array.from(document.querySelectorAll('a[href]')).map(a => a.getAttribute('href')).filter(h => h && (h.startsWith('/') || h.startsWith(window.location.origin))))])")

Log discovered routes:

{"timestamp":"...","agent":"inventory-javascript-mapper","action":"experiment","technique":"react-router-registry","routes_found":23,"source":"window.__routes"}

Phase 3: Test

1. For each discovered route, navigate to it and capture the page:

   browser_navigate(url="https://TARGET/dashboard")
   browser_snapshot()
   browser_network_requests()

Record: page title, new AJAX endpoints triggered, authentication state (redirect to login vs. content rendered). 2. Identify auth-protected routes (navigate and detect redirect to login):

   browser_navigate(url="https://TARGET/admin")
   browser_evaluate(function="() => window.location.href")

If redirected to /login — route is auth-protected. If content rendered — route is accessible. 3. Extract dynamically-loaded JavaScript file URLs:

   curl -s https://TARGET | grep -oE 'src="(/[^"]*\.js[^"]*)"' | sort -u \
     | tee outputs/ENGAGEMENT/activity/js-files-TARGET.txt

4. Download and search JS bundles for hardcoded routes and API endpoints:

   # For each JS file found, download and grep for route patterns
   curl -s https://TARGET/static/js/main.chunk.js \
     | grep -oE '"/[a-zA-Z0-9/_-]+"' | sort -u \
     | tee outputs/ENGAGEMENT/activity/js-routes-extracted-TARGET.txt

5. Check for localStorage and sessionStorage content after navigation:

   browser_evaluate(function="() => JSON.stringify({ localStorage: Object.keys(localStorage), sessionStorage: Object.keys(sessionStorage) })")

6. Log:

   {"timestamp":"...","agent":"inventory-javascript-mapper","action":"test","route":"/admin","auth_required":true,"redirect":"/login"}
   {"timestamp":"...","agent":"inventory-javascript-mapper","action":"test","route":"/dashboard","auth_required":false,"ajax_calls":["/api/v1/metrics","/api/v1/users/me"]}

Phase 4: Verify

1. Write `outputs/ENGAGEMENT/inventory/javascript-routes.json`: Array of route objects:

   [
     {"route": "/", "type": "public", "title": "Home", "ajax
Read more
@stickman230
Ships withclaude-pentest

An open source plugin for enabeling claude to gain offensive pentesting capabilities

1377 skills15 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
137
Star history of Stickman230/claude-pentest on GitHub, a chart by star-history.com

Other agents on claude-pentest.

csrf-tester

csrf-tester

Agent

Tests for CSRF vulnerabilities including missing tokens, weak validation, SameSite bypass, token reuse, and method override.…

cve-tester

cve-tester

Agent

Identifies technology stacks, researches known CVEs in NVD/Exploit-DB/GitHub, adapts public PoC exploits, and validates…

More agents from other plugins.

dependency-review

dependency-review

Agent

<!-- SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. --> <!--…

@nvidia@nvidiaInstall Agent
autopilot

autopilot

Agent

Autonomous hunt loop agent. Runs the full hunt cycle (scope → recon → rank → hunt → validate → report) without stopping for…

@awarexone@awarexoneInstall Agent
autopilot

autopilot

Agent

Autonomous hunt loop agent. Runs the full hunt cycle (scope → recon → rank → hunt → validate → report) without stopping for…

@shuvonsec@shuvonsecInstall Agent

Questions about inventory-javascript-mapper.

Which coding agents can use inventory-javascript-mapper?
inventory-javascript-mapper installs in Claude Code and Cursor: each loads subagents from .claude/agents, so copy the file there. Flowy's auto-invocation runs in Claude Code only.