Welcome to the fourth lesson of our DAST course. In the previous lessons, we used ZAP and Nuclei to scan the public-facing areas of an application. We checked for default credentials on login pages and looked for exposed debug endpoints. However, most modern applications hide their most sensitive functionality — like payment processing, user settings, and administrative controls — behind a login screen. If your scanner cannot log in, it is effectively blind to the majority of the application's attack surface.
In this lesson, we will tackle Authenticated Scanning. We will configure our tools to act like a legitimate user by handling login flows, managing session tokens, and maintaining active sessions. This allows us to discover critical vulnerabilities that unauthenticated scans miss, such as IDOR (Insecure Direct Object References), broken access controls, and privilege escalation issues. By the end of this lesson, you will be able to automate the entire authentication process, allowing your scanners to patrol the private areas of your application.
To perform an authenticated scan effectively, we must first define the boundaries of our target. In OWASP ZAP, we use a Context. A Context is essentially a container that defines a specific web application or a subset of it. It tells ZAP which URLs belong to the application we want to test and which ones should be ignored. This is particularly important for authentication because we need to associate specific users and login methods with a specific set of URLs.
Without a Context, ZAP treats every URL equally. When we introduce authentication, we need to tell ZAP exactly where the authentication rules apply. For example, we might want to scan our API endpoints running on localhost:3001 as an Admin user, but we do not want to accidentally send those credentials to third-party sites like Google Analytics that might be loaded by the page.
Here is how we create a new context and define its scope using the ZAP API. We use Regular Expressions (Regex) to tell ZAP to include any URL that matches our API pattern.
The regex http://localhost:3001/api/.* acts as a wildcard. It tells ZAP that any URL starting with that prefix belongs to the pastebin-auth context. Now, any configuration we apply to this context — such as users or login methods — will automatically apply to these URLs.
Modern web applications, especially Single Page Applications (SPAs), typically use JSON-Based Authentication. Instead of submitting a traditional HTML form, the browser sends a JSON object (usually containing a username and password) to an API endpoint. ZAP needs to know exactly how to format this request so it can log in successfully during a scan.
We configure this using the setAuthenticationMethod API endpoint. We must provide the Login URL and the Login Request Data. In the request data, we use special placeholders like {%username%} and {%password%}. ZAP will replace these placeholders with actual credentials when it attempts to log in.
However, sending the login request is only half the battle. ZAP also needs to know whether the login was successful. We do this by setting a Logged-In Indicator. This is a Regex pattern that ZAP looks for in the response. If the pattern is found, ZAP knows it is authenticated. For our API, a successful login returns a JSON object containing a token, so we use that as our indicator.
If ZAP sends the credentials but does not see the token string in the response, it will assume the login failed and report an error. This feedback loop is essential for automated scanning.
Now that ZAP knows how to log in, we need to tell it whom to log in as. We do this by creating a User within our Context. A context can have multiple users (e.g., Admin, Editor, Viewer), which is useful for testing authorization flaws where a low-level user tries to access admin features. For this lesson, we will create a standard user named testuser.
After creating the user, we must assign Credentials. These are the actual values that will replace the {%username%} and {%password%} placeholders we defined earlier.
To make sure ZAP actually uses this user for our scans, we enable Forced User Mode. When this mode is active, ZAP intercepts every request that matches our Context and automatically forces it to be authenticated as the specified user. If the session expires or the token becomes invalid, ZAP automatically re-authenticates in the background.
With Forced User Mode on, you do not need to manually attach headers or cookies. ZAP handles the session management entirely, allowing you to focus on the scan logic.
With our Context, Authentication, and User configured, we are ready to launch an attack. The process is similar to the unauthenticated scans we ran in Lesson 2, but this time we explicitly specify the contextName. First, we run the Spider to crawl the application. Because we are authenticated, the Spider will be able to find pages that were previously hidden, like /api/settings or /api/private-data.
Once the Spider has mapped out the protected endpoints, we run the Active Scan. This injects payloads into the authenticated routes. This is where we often find the most critical vulnerabilities. For example, ZAP might try to inject SQL commands into a Change Password field that is only accessible after logging in.
The alerts returned from this scan will specifically pertain to the authenticated surface area. Finally, just like before, we can export these findings into an HTML report to share with the development team.
While ZAP is excellent for broad, heavy scanning, Nuclei shines when you need to perform complex, logic-based checks. One common vulnerability in APIs is IDOR, where a user can access another user's data by providing a resource identifier (like a UUID) that belongs to someone else. While many modern applications use unguessable IDs like UUIDs instead of simple integers (e.g., /api/snippets/1 vs /api/snippets/b29384-a129...), the underlying flaw remains: the server fails to verify if the requesting user actually owns the resource.
To test this with Nuclei, we can authenticate as one user, and then attempt to access a resource ID that we know belongs to a different user.
In the second request, we use Authorization: Bearer {{auth_token}}. Nuclei automatically replaces {{auth_token}} with the value it grabbed from the first request. If the server returns a 200 OK for a resource that the admin user shouldn't own, it means we successfully discovered an IDOR or access control bypass. This logic allows us to chain multiple requests together to simulate complex user behaviors.
In this lesson, we unlocked the full potential of DAST by learning how to break through the login barrier. We explored ZAP Contexts to define our scan scope and configured JSON-Based Authentication to teach ZAP how to communicate with modern APIs. We also utilized Forced User Mode to automate session management, ensuring every request is properly authenticated. Finally, we updated our understanding of IDOR to handle modern identifiers like UUIDs and wrote a multi-step Nuclei Template to test for these logic flaws.
Now, it is your turn to put this into practice. In the upcoming exercises, you will use the ZAP API to configure a full authenticated scan against our Pastebin application. You will create the user, set the credentials, and launch a scan to find vulnerabilities that were previously hidden from view. You will also write a custom Nuclei template to verify whether users can access data they should not. Let's get to work!
