WebApp Testing — API Coverage & Test Selection¶
During a WebApp scan, the browser engine captures every API request the application issues while it is being crawled. The API Coverage view lists these requests and shows, per endpoint, which security checks were executed against them.
This page explains the difference between captured and tested, and documents every reason an endpoint that returned a successful response during the scan may still appear with no security checks applied.
Captured ≠ Tested¶
WebApp Testing splits API handling into two distinct phases:
- Capture: The browser observes an API request while navigating the application. The raw request/response is recorded and appears in the API Coverage logs (this is what produces the
200entries you see in the coverage view). - Active testing: After capture, the request is passed through a series of filters. Only requests that survive every filter are sent to the security-check engine for active fuzzing (injection payloads, IDOR, mass-assignment, etc.).
A request can therefore be captured and successful (HTTP 200) without ever being actively tested. This is by design — the filters exist to keep scans fast, safe, and focused on meaningful attack surface.
Why does this matter?
An endpoint visible in the API Coverage logs with a 200 response is evidence that the scanner reached the endpoint. The absence of security-check activity on that endpoint is not a bug — it is the result of one of the deterministic filters described below.
Why a Captured Endpoint May Not Be Tested¶
When an endpoint shows up in the coverage logs with a successful response but no downstream security checks, it will always be for one of the reasons below. Going through this checklist in order is the fastest way to diagnose the situation.
1. API_CHECKS Is Not Enabled¶
The security_checks_enabled list controls which check families run during the scan. If API_CHECKS (or ALL) is not included, captured API traffic is recorded but never forwarded to the security-check engine.
frontend_dast:
security_checks_enabled:
- API_CHECKS # Required for active testing of captured API traffic
# - PASSIVE_PAGE_CHECKS
# - NETWORK_CHECKS
# - ACTIVE_PAGE_CHECKS
See Performance Tuning — Security Check Selection for the complete check-type reference.
2. The Endpoint Is Out of the API Testing Scope¶
Two layers of scope apply, in this order — both must be satisfied for an endpoint to be tested:
-
Exploration scope (top-level
scope.allowlist,type: domain): defines every domain the scanner is allowed to reach. Traffic to a domain not in the exploration scope is dropped before any security check considers it. This is the most common reason a frontend-to-API call on a different hostname (e.g.api.example.comcalled by a frontend onapp.example.com) is not tested. See Exploration Scope for how to extend it. -
API testing scope (
frontend_dast.scope.api_testing): within the exploration boundary, fine-grained allowlist/blocklist rules control which captured traffic is actively tested. Two independent mechanisms apply:- Allowlist: If an allowlist is configured, only requests matching at least one allowlist rule are testable. Everything else is captured into logs but skipped for active testing.
- Blocklist: Requests matching a blocklist rule are always captured (for visibility) but never actively tested — this is the recommended way to exempt authentication, logout, payment, or destructive endpoints from fuzzing.
frontend_dast:
scope:
api_testing:
allowlist:
- type: domain
value: "api.example.com"
blocklist:
- type: rest_api_path
value: "/api/auth/.*" # captured, but no security checks run
operation: regex
See Scope Configuration — API Testing Scope for the full rule reference.
Blocklist ≠ network-level block
The api_testing blocklist prevents the scanner from actively testing matching endpoints and prevents the crawling agent from directly navigating or calling them. It does not intercept requests that the application itself issues from the browser. If a page in scope issues an XHR/fetch call to a blocklisted endpoint as part of its normal rendering, the browser will still execute that request — it will appear in the coverage logs as captured but will be skipped by the security-check engine. See Scope Configuration — What the blocklist does and does not prevent today.
3. The Request Was Captured During the Authentication Phase¶
By default, API traffic generated while the scanner is establishing its authenticated session is recorded but not fuzzed. Running active security checks against login, token-exchange, or refresh endpoints while the scanner is still authenticating can invalidate the session and destabilize the entire scan.
This behavior is controlled by api_checks_during_auth:
Setting it to true enables active testing of auth-phase traffic, at the cost of occasional session instability. See Production-Safe Scanning for the trade-offs.
4. The Endpoint Is a Duplicate of One Already Tested¶
The scanner fingerprints each exchange on the tuple (full URL, HTTP method, request body, response status, response body). When a second exchange with the same fingerprint is captured, it is recorded in the coverage view but not re-submitted to the security-check engine — the first exchange already exercised the same code path.
This means that in coverage logs you can legitimately see:
- Multiple
200entries for the same endpoint (e.g. polling, pagination with identical responses, repeated list calls) - Only one of them marked as actively tested
This deduplication is deliberate and significantly reduces scan duration without reducing real coverage. There is no configuration knob — the fingerprint is computed per exchange.
5. Read-Only (Production) Scan Mode¶
When the scan is configured as Read-Only, destructive HTTP methods are automatically blocklisted for active testing:
- REST:
POST,PUT,PATCH,DELETE - GraphQL:
mutationoperations
These requests are still captured (the browser issues them naturally during crawling, and they appear in the coverage view with their real response), but security checks are not executed against them. See the Read-Only scan mode documentation for the full list.
6. The Scan's Time Budget Was Exhausted¶
Active security checks run inside the scan's max_duration budget. When the budget is consumed (usually because crawling took longer than expected, or because many parameter variations were explored), the remaining captured endpoints are left in the coverage logs without their security checks executing.
Symptoms:
- The coverage view shows many endpoints with successful captures and no test activity, concentrated toward the end of the scan timeline
- The scan status indicates it reached the time limit
Remediation:
- Increase
max_duration - Reduce exploration through
crawling_tuninglimits and crawling blocklists (see Performance Tuning — Crawling Efficiency) - Narrow the API Testing Scope allowlist to focus time on the endpoints that matter
- Enable
prefetch_sitemapand populatehotstartwith known entry points
7. Schema Inference Failed for That Request¶
Before fuzzing, the scanner infers an OpenAPI-style schema for each captured request so that payloads can be generated and mutated meaningfully. If schema inference fails for a specific exchange (non-JSON bodies, malformed responses, unexpected content types), that exchange is dropped from the active-testing pipeline. It remains in the coverage logs as a successful capture.
This is rare for standard REST and GraphQL APIs and typically affects:
- Binary endpoints (file uploads/downloads, images, streamed media)
- Endpoints returning non-parseable responses
- Endpoints with dynamically structured bodies that the inference engine cannot generalize
Quick Diagnostic Checklist¶
When an endpoint in the API Coverage view shows a 200 response but no test activity, walk through the following checks in order:
| # | Check | Where to look |
|---|---|---|
| 1 | Is the endpoint's domain present in the top-level scope.allowlist (exploration scope)? | Scan configuration |
| 2 | Is API_CHECKS (or ALL) present in frontend_dast.security_checks_enabled? | Scan configuration |
| 3 | Does the endpoint match the scope.api_testing allowlist and not match the blocklist? | Scan configuration |
| 4 | Was the request captured during login / token refresh / MFA? | API Coverage logs — timestamp before authenticated crawl |
| 5 | Does an earlier exchange have the same URL + method + request body + response? | API Coverage logs — compare rows for the same endpoint |
| 6 | Is the scan in Read-Only mode and the request uses POST / PUT / PATCH / DELETE / mutation? | Scan mode setting |
| 7 | Did the scan finish within max_duration, or was it cut short? | Scan summary — compare elapsed time against configured max |
| 8 | Is the request's body or response in a non-JSON / binary format? | API Coverage logs — content type of the exchange |
If all eight checks pass and the endpoint still shows no active testing, contact Escape support with the scan ID and the endpoint URL — this indicates an unexpected condition that should be investigated.
Related Documentation¶
- API Coverage (API DAST) — coverage status definitions shared across scanner kinds
- Performance Tuning — controlling
max_durationand security-check selection - Scope Configuration — configuring API testing allowlists and blocklists
- Production-Safe Scanning — Read-Only mode and
api_checks_during_auth - Configuration Reference — full parameter reference