Route Discovery in SPAs: Security Testing with Headless Browsers
Single Page Applications (SPAs) have become the standard for modern web development. Frameworks like React, Vue, and Angular handle routing on the client side, which creates unique challenges for security testing. Traditional directory enumeration tools like gobuster or dirb rely on HTTP status codes, but SPAs often return the same status code for all routes, making them invisible to these tools.
In this article, I’ll walk you through building a custom route discovery tool called “Route Hunter” that uses headless browser automation to find hidden routes in SPAs. This demonstrates how modern web applications require different security testing approaches.
Why Traditional Enumeration Tools Fail
Traditional directory enumeration tools work by sending HTTP requests to various paths and analyzing the response status codes. A 200 OK typically means the path exists, while 404 Not Found means it doesn’t. However, SPAs break this assumption.
In a typical SPA:
- All routes are handled by JavaScript on the client side
- The server often returns the same HTML file (usually
index.html) for all routes - The JavaScript router then determines what content to display
- HTTP status codes don’t reflect whether a client-side route exists
This means traditional tools will miss client-side routes entirely, leaving potential attack surfaces undiscovered.
What is SPA Route Enumeration?
SPA route enumeration is a specialized reconnaissance technique used to discover client-side routes in JavaScript-heavy web applications. Unlike traditional server-side directory enumeration, SPA route enumeration requires rendering the JavaScript application in a browser to detect routes.
Modern SPAs use client-side routing (React Router, Vue Router, Angular Router, etc.) where routes are handled by JavaScript rather than the server. These routes may not return different HTTP status codes, making them invisible to traditional enumeration tools.
Route Hunter uses differential analysis by comparing page characteristics (title, H1 headings, content length) against a baseline to identify valid routes, even when they don’t trigger server-side responses.
Why This Matters
SPA route enumeration is particularly important as modern web applications increasingly rely on client-side routing. Traditional enumeration tools fail to detect these routes because they don’t trigger different HTTP responses. Understanding how SPAs handle routing and how to enumerate client-side routes is crucial for comprehensive security assessments.
Building custom enumeration tools demonstrates deeper understanding of browser automation, JavaScript rendering, differential analysis techniques, and security testing methodologies. This knowledge is essential for testing modern web applications that heavily rely on client-side frameworks.
Building Route Hunter: A Custom SPA Enumeration Tool
Let’s build a custom tool that can discover routes in SPAs. I’ll call it “Route Hunter” and implement it using Python and Selenium WebDriver.
Tool Architecture
The tool needs to:
- Load a wordlist of potential route names
- Navigate to each potential route in a browser
- Compare the page characteristics against a baseline
- Identify routes that differ significantly from the baseline
- Support both hash-based routes (
/#route) and History API routes (/route)
Tool Structure
route-hunter/
├── route_hunter/
│ ├── __init__.py
│ ├── cli.py (CLI interface and argument parsing)
│ └── hunter.py (Core Selenium-based route discovery logic)
├── setup.py (Python package configuration)
├── README.md (Documentation)
└── requirements.txt (Dependencies: selenium, webdriver-manager)
Core Implementation
The core logic uses Selenium WebDriver to:
- Create a baseline from the base URL
- Extract page information (title, H1, content length)
- Test each potential route
- Compare against the baseline using differential analysis
- Report routes that differ significantly
Here’s a conceptual example of the core approach:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
class RouteHunter:
def __init__(self, base_url, headless=True):
self.base_url = base_url
self.baseline = None
# Initialize headless browser
self.driver = webdriver.Chrome(options=Options())
def create_baseline(self):
"""Create baseline from base URL."""
self.driver.get(self.base_url)
# Wait for page to load
# Extract baseline characteristics
self.baseline = {
'title': self.driver.title,
'h1': self._get_h1(),
'content_length': len(self.driver.page_source)
}
def test_route(self, route):
"""Test a route and compare against baseline."""
self.driver.get(f"{self.base_url}/{route}")
page_info = {
'title': self.driver.title,
'h1': self._get_h1(),
'content_length': len(self.driver.page_source)
}
# Compare: title/H1 differs OR content length >10% difference
if self._differs_from_baseline(page_info):
return page_info
return None
Using Route Hunter
Installation and Usage
The tool requires Python with Selenium WebDriver. Basic usage involves:
pip install selenium webdriver-manager
python3 route_hunter.py http://localhost:3000 wordlist.txt --headless
The tool tests routes from a wordlist, comparing each against the baseline to identify valid client-side routes.
Example Output
The tool provides output showing discovered routes:
[*] Creating baseline from http://localhost:3000...
[+] Baseline created successfully
[*] Progress: 100/2000 URLs tested, 2 routes found
[+] Found: http://localhost:3000/#/administration
Title: Administration
[+] Found: http://localhost:3000/#/complain
Title: Customer Feedback
============================================================
RESULTS
Discovered routes: 5
Total URLs tested: 2000
============================================================
Differential Analysis Explained
The key to Route Hunter’s effectiveness is differential analysis. Instead of relying on HTTP status codes, we compare page characteristics:
- Title Comparison: Different routes often have different page titles
- H1 Comparison: Headings typically change between routes
- Content Length: Significant differences in content length can indicate different pages
The tool uses a two-rule system:
- Rule 1: Title or H1 differs from baseline
- Rule 2: Content length differs by more than 10%
If either rule is true, the route is considered valid. This approach is more reliable than HTTP status codes for SPAs.
Security Implications
Route enumeration exposes critical security risks:
Information Disclosure
Hidden endpoints may expose sensitive data, configuration files, backup files, or API documentation that reveals application structure and potential attack vectors.
Unauthorized Access
Discovered administrative panels or API endpoints may have weak authentication or be misconfigured, allowing unauthorized access to sensitive functionality.
Attack Surface Expansion
Each discovered endpoint increases the potential attack surface, providing more opportunities for exploitation of vulnerabilities.
Business Impact
Exposed endpoints can lead to data breaches, service disruption, or compliance violations, especially if they reveal customer data or internal business logic.
Real-World Examples
- GitHub (2019): Exposed AWS credentials through discovered
.envfiles in public repositories - Multiple incidents: Backup files (
.bak,.old) discovered through enumeration have led to source code leaks and credential exposure
Mitigation Strategies
1. Implement Proper Route Protection
Ensure all client-side routes, especially administrative or sensitive ones, require proper authentication and authorization.
// SECURE - Protected route with authentication check (React Router)
<Route
path="/administration"
element={
<RequireAuth>
<AdminPanel />
</RequireAuth>
}
/>
2. Implement Rate Limiting and Bot Detection
Implement rate limiting and bot detection mechanisms to identify and block automated enumeration attempts.
// Server-side rate limiting
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100
});
app.use(limiter);
3. Minimize Information Disclosure
Avoid using obvious route names like /admin, /api, /secret. More importantly, ensure routes are properly protected regardless of their names. Validate routes on the server side when possible - don’t rely solely on client-side routing for sensitive functionality.
Security Best Practices
- Regularly perform security audits to identify and secure all exposed endpoints
- Use Web Application Firewalls (WAF) to detect and block enumeration attempts
- Implement proper logging and monitoring to detect scanning activities
- Use robots.txt appropriately (but don’t rely on it for security)
- Consider using non-standard endpoint names for sensitive functionality (though this is security through obscurity)
- Implement CAPTCHA or other bot detection mechanisms for sensitive endpoints
- Use authentication tokens and API keys properly, and rotate them regularly
- Document all endpoints and maintain an API inventory
Lessons Learned
Building Route Hunter provided valuable insights into SPA security testing:
Technical Insights
- SPA route enumeration requires different techniques than traditional directory enumeration
- Browser automation is essential for JavaScript-heavy applications
- Differential analysis is more reliable than HTTP status codes for client-side routes
- Selenium WebDriver enables JavaScript rendering and client-side route detection
- Headless mode is essential for automation and integration into security testing pipelines
Tool Development Insights
- Baseline comparison helps avoid false positives from dynamic content
- Supporting both hash-based and History API routes covers different SPA routing strategies
- CLI design and user experience are important even for security tools
- Checkpoint/resume functionality is crucial for long-running scans
- Tool development skills are valuable for creating specialized tools tailored to specific testing scenarios
Security Insights
- Route enumeration is often the first step in penetration testing
- Discovered routes can reveal SPA architecture and potential attack vectors
- Custom tools allow for specific feature additions that may not be available in standard tools
- Building tools from scratch provides valuable learning opportunities
Conclusion
SPA route enumeration is a crucial skill for modern security testing. Traditional enumeration tools fail to detect client-side routes, requiring new approaches that leverage browser automation and differential analysis.
Building custom tools like Route Hunter not only helps discover hidden routes but also deepens understanding of how modern web applications work and how to test them effectively. The ability to create specialized tools tailored to specific testing scenarios is a valuable skill in security testing.
Remember: route enumeration is just the first step. Once routes are discovered, they should be analyzed for vulnerabilities, authentication bypasses, and information disclosure. Always ensure you have proper authorization before performing any security testing.
References & Further Reading
- OWASP Top 10 - A05:2021 Security Misconfiguration
- OWASP Testing Guide - Information Gathering
- Selenium WebDriver Documentation
- SecLists - Collection of wordlists
- Python Selenium Package
- Single Page Application Security - OWASP
Disclaimer: All security testing discussed in this article was performed in a controlled, legal environment using OWASP Juice Shop, an intentionally vulnerable application designed for security training. Never attempt these techniques on systems you don’t own or have explicit permission to test.
Related Articles
Persistent XSS Through APIs: A Practical Analysis
December 17, 2025
Exploring how persistent XSS vulnerabilities can be exploited through API endpoints and how to prevent them
Understanding XSS: Cross-Site Scripting Basics
December 15, 2025
A comprehensive introduction to Cross-Site Scripting (XSS) attacks, covering types, techniques, and defense strategies
Understanding Brute Force Attacks: From Theory to Practice
November 10, 2025
A practical guide to brute force attacks, demonstrating exploitation techniques and mitigation strategies using OWASP Juice Shop