OWASP Zed Attack Proxy (ZAP) is one of my favorite tools for scanning and performing vulnerability tests on a web application. It has a simple GUI to get started, with a large capability for customization to tailor scans as needed.

Recently, I was faced with a problem to login and then scan the authenticated segments of the web application. Seems easy: pass in the username and password fields and define their parameters. Except the post request also required a token parameter for added security. This token is obtained within the Javascript header on the landing page.

Below is an excerpt of the code on the landing page.


If the token is not included with the login script as a POST parameter, the request will be rejected. Below is a sample request header, with the POST parameters included under the Form Data. To not be outright rejected, and have a custom 500 error page return, the _token must equal the value of the csrf-token.


This presented a challenge beyond ZAP’s Basic Authentication scripting capabilities. Simply getting ZAP to enter the username and password, as prompted by the application is unsuccessful as it is unable to automatically extract the token value. Attempting to spider or access pages that require authentication result in 500 or 405 errors. The application returned a custom 500 error when failing to access a given page. These error codes indicated that ZAP could not load the correct page.

ZAP scanned only a limited portion of the application, as most of the pages and features required authentication.

Enter Zest, the ZAP scripting language. This language is built around accomplishing tasks, such as fuzzing data, traversal through a website, or logging in. Simon Bennet gives a fantastic basic crash course demo on YouTube for how to work with Zest.


As the authenticated login for this website was a bit complicated, a custom script was needed. There were several different methods of constructing the Zest scripts to perform the scan. By far the easiest is to Record a new Zest Script.

Clicking the button, shown below, in the top navigation bar brings up a popup menu to record all of the actions performed.


For this script, I began the recording at the landing page of the web application. When ZAP recorded this page, it gathered the token, and learned to serve it with the login parameters. This recording extracted the token and automated the login process.

After creating these scripts with Zest, be sure to remove extra steps or page calls to simplify the repeatable process.

In my case, the login steps required only 3 steps: start at the landing page, submit the login, and redirect to the authenticated landing page. Along the way, there were dozens of pages and files accessed to help visually display the page. These page loads were unnecessary for login, so they were removed from the script.

The end result is the script containing the 3 requests shown:


Test the Zest script by pressing the Run button. This executes the script. A 200 HTTP response on the authenticated page indicates the script successfully logged in.


A custom Context is used to apply the Login Script from Zest to run the recorded tasks.



To get the best results, spider the site first using the Context to find all of the authenticated pages that are available. Then an Active Scan is performed on each page identified.

One mistake I discovered was to ensure that the Forced User Mode button is not selected.


The locked icon needed to be set to unlocked. 04_08

Otherwise the token was fixated to the value used when creating the Zest script and not renewed with each test execution. This was very frustrating to overlook as it caused the script to work, but the login attempts to fail.

Another problem was that the login URL for the Zest script needed to begin at the starting homepage and not the login page to work properly. For this web application, the token was set the first time the user accesses the homepage. Therefore, the scripts needed to start at that page to obtain a new token before moving to login.

To do this, set the LoginURL to the starting page within the Context settings. In this case, I needed to use the LoginURL of the homepage, https://[myapp], instead of the login page at https://[myapp]/auth/login.

6 thoughts to “Scripting Authenticated Login within ZAP Vulnerability Scanner

  • anonym

    nice tutorial esp, tips in last paragraph, thanks

  • Akshay

    Hey Ben,
    I’ve recorded the zest script to fetch the token. Now I have to call the API through my code to execute spider and then active scanner. How can I use this token in my API. Is there any better way to tell the spider to login and start spidering for form authenticated pages?


  • Ben Pick

    Hi Akshay,

    The zest script is recorded as a context file, which handles the gathering of the token for you. This entire context may be imported and used in a python script with the following:
    zap.context.import_context(‘/contextFile.context’, apikey = api)
    zap.spider.scan_as_user(, , , subtreeonly = True, apikey = api)
    I am not sure what programming language you are using, but I highly recommend python for integrating with zest. Unfortunately, I do not know of a way to extract the token from a running zest instance. However, the above lines work within the framework of the zest scripting language.

    Good luck.

    Ben Pick

  • Oren

    Hi there, after reading this amazing post i am too delighted to share my knowledge here with friends.

  • Andre Guerra

    Thank you for this article. I assume since you have disabled the forced user, it is also not required to have an user/password setup in the User menu inside the Context. Is that correct?

  • Mubbashir

    Hello Ben, I can see from the screenshot the script is recorded under Authentication node. Can we create a Stand Alone zest script for authentication. I tried to create stand alone script but it wasn’t loading when we select ‘Script based Authentication’


Leave a comment

Your email address will not be published. Required fields are marked *