Key Technology

Find the server endpoints your scanner can't reach

Dynamic crawlers only find endpoints they can trigger from the UI. Dead code and auth-gated bundles hide real server endpoints in client-side JavaScript — SolidPoint's static analysis finds them.

The Problem

What dynamic crawling misses

Dynamic crawlers discover endpoints by simulating user interaction — clicks, form submissions, navigation. Three categories of server endpoints regularly escape this approach:

1

Dead code — functions that exist in the JavaScript bundle but are never called from the UI. No interaction can trigger them.

2

Uninstantiated modules — API client classes and request helpers that are shipped in the bundle but not used on the current page.

3

Auth-gated bundles — JavaScript for admin panels, authenticated features, and debug interfaces shipped to all users, including anonymous ones. The UI hides these features, but the code — and the server endpoints it references — is right there.

Example: Dead code with a live server endpoint
1  const api = "/application/iuT6ei/";
2  const remove = async (params) => {
3    if (prompt("Enter 'yes' to remove") !== "yes") return;
4    await fetch(api + "interface/remove/handle", {
5      method: "POST", body: JSON.stringify(params)
6    });
7  };
8  const removeByID = (id) => remove({ ident: id });

These functions are never called anywhere on the page. No button triggers them. No link references them. A dynamic crawler simulating user clicks will never execute this code. But the fetch call on line 4 references a live server endpoint that a scanner should test. In our research, we found this exact pattern in a WordPress plugin with 70,000+ active installations.

Example: Uninstantiated API client class
1  class ApiClient {
2    baseURL = '/api/v2/';
3
4    async sendData(payload) {
5      await fetch(this.baseURL + 'data/ingest', {
6        method: 'POST', body: JSON.stringify(payload)
7      });
8    }
9  }

If this class isn't instantiated on the page, the fetch call on line 5 is invisible to crawlers. Regex URL matching won't find it either — the URL is split across a class field and a method and requires resolving this.baseURL. Industry scanners tested in our research — including Acunetix, Burp Scanner, HCL AppScan, Detectify, and PT BlackBox Scanner — found zero hidden endpoints in code like this.

These are not edge cases. In our testing of five benchmark applications, we found client-side JavaScript bundles containing endpoints for admin panels, authenticated features, disabled functions, and debug interfaces. The server-side code behind these endpoints was live and potentially exploitable.

Our Approach

How SolidPoint's static analysis works

Every scanner crawls HTML and simulates clicks. SolidPoint adds a third layer:

1

Static crawling

HTML links, forms, and standard markup. The baseline every scanner does.

2

Dynamic crawling

Headless browser interaction — simulating clicks, form submissions, and navigation.

3

JavaScript static analysis

AST-level analysis of all JavaScript on the page, including dead code and auth-gated bundles. This is SolidPoint's differentiator.

Deep Dive

Inside the static analysis engine

Multi-pass analysis

Four passes over the JavaScript AST accumulate knowledge about variable values, function arguments, and return values — building a progressively more complete picture of the program's data flow.

Call-chain traversal

Traces data flow through up to 5 levels of nested function calls — resolving arguments, return values, and shared global variables across callers.

Dead code analysis

Visits all AST nodes regardless of reachability — including never-called functions and dead branches. Code that dynamic analysis skips entirely.

Auth-gated discovery

Client-side JS bundles often ship code for admin panels and authenticated features to all users. The analyzer finds those endpoints without credentials.

OOP and class resolution

Resolves this in ES6 classes and prototype-based patterns. Tracks baseURL through constructor assignment to method usage.

AJAX sink recognition

Identifies request-sending patterns across fetch, jQuery $.ajax/$.post, axios, AngularJS $http, and window.location assignment.

Bundler-aware module resolution

Recognizes Webpack and Browserify bundle structures, extracts individual modules, and resolves require() calls and exports across module boundaries.

Whole-page analysis

Analyzes all scripts on the page as a single unit — resolving globals set in inline script tags and used in external JavaScript files.

Published Research

Peer-reviewed and journal-published

Sigalov, D., Gamayunov, D. "Finding Server-Side Endpoints with Static Analysis of Client-Side JavaScript." ESORICS 2023 Workshops, LNCS vol. 14399, pp. 442–458. Springer, 2024.

First method to apply nontrivial static analysis of client-side JavaScript for discovering server endpoints in black-box security scanning. Published at the European Symposium on Research in Computer Security and expanded into a full journal article in Elsevier's Journal of Information Security and Applications. Research by Daniil Sigalov and Dennis Gamayunov (Lomonosov Moscow State University / SolidSoft LLC).

View on Springer →

Evaluation results

On OWASP Juice Shop — a single-page app that ships all API client code to unauthenticated users — our analysis found 36 server endpoints. The best dynamic crawler found 13.

On MyBB, we found 77 endpoints. The next best result was 68 (Arachni).

We tested five industry scanners — Acunetix, Burp Scanner, HCL AppScan, Detectify, and PT BlackBox Scanner — against a benchmark with 17 endpoints (14 hidden). None found any hidden endpoints. Our prototype found all 17.

Results vary by application complexity. On WebGoat, whose client-side JS uses class inheritance and AMD bundlers beyond our current support, the best dynamic crawler (Arachni) found 78 endpoints vs. 12 for static analysis. This is why we use both methods together.

Analysis completed in under 30 seconds per page across all benchmarks. Full-application analysis of MyBB (longest run) took 5 minutes.

Open-source components and full experiment data are publicly available for verification.

Why It Matters

Why hidden endpoints matter

Every endpoint your scanner misses is an endpoint that gets zero vulnerability testing. It sits in production, untested, until someone finds it.

Missing endpoints often mean missing access controls

Admin panels, authenticated features, and debug interfaces accessed through hidden endpoints frequently lack server-side authorization checks — the UI was the only gate. When a scanner finds these endpoints and tests them, Broken Access Control vulnerabilities surface. When it doesn't, they don't. Broken Access Control has been the #1 category in the OWASP Top 10 since 2021.

OWASP Top 10 #1 since 2021

Incomplete discovery means incomplete coverage

In our benchmark testing, the best dynamic crawler found 13 endpoints on a single-page application where 36 existed. Those 23 untested endpoints included API routes for file upload, user administration, and data export — functionality that was live on the server and accepted unauthenticated requests.

Best crawler found 13 of 36 endpoints

Your compliance scope has a blind spot

PCI DSS 4.0.1, SOC 2, and ISO 27001 require web application security testing. These frameworks assume your scanner is testing the full application. If endpoint discovery is incomplete, your testing scope is incomplete — and no audit will catch the gap, because the missing endpoints aren't in any report.

Affected frameworks PCI DSS · SOC 2 · ISO 27001
Comparison

What each discovery method finds

Discovery capability Dynamic crawling Regex URL matching SolidPoint static analysis
HTML links and forms Yes N/A Yes
UI-triggerable JS requests Yes Partial Yes
Dead code (never-called functions) No Partial Yes
Auth-gated endpoints (admin panels) With credentials * Partial Yes
URLs built from variables in dead code No No Yes
Uninstantiated class methods No No Yes
Call chains in untriggerable code (3–5 levels) No No Yes

* Only with valid credentials for that role. Without authentication, dynamic crawlers miss these entirely.

Transparency

What we don't cover yet

Static analysis of JavaScript complements dynamic crawling — it doesn't replace it. Our analyzer works alongside headless browser crawling and traditional static crawling. Together, the three layers produce the most complete attack surface map.

Some JavaScript patterns remain challenging for static analysis: complex framework-specific event systems, class inheritance hierarchies, and endpoints constructed entirely from DOM data at runtime. We are actively expanding coverage in these areas.

Uygulama Güvenlik testinizi bugün bizimle artırmaya başlayın

Ücretsiz dene Demo al