ClientSpider & client Authentication via Zest

97 views
Skip to first unread message

MERIEM MELLOUS

unread,
Apr 17, 2026, 10:43:51 AMApr 17
to ZAP User Group
Hello ,  I noticed that when launching the following AF, the spider does consider my authentication Zest script  but when it comes to clientSpider it doesn't authenticate. I made sure that my authentication config in the env is "client" authentication as I saw in the documentation that normally this way the clientSpider or the AjaxSpider are supposed to automatically consider authentication script.
I used the Zap browser extension to record my authentication script.
 I do enable httpSender first so that I get the accesstoken from a specific response and then declare it as a script global var "myvar" .


env:
parameters:
failOnError: true
failOnWarning: false
progressToStdout: true
contexts:
- name: mycontext
urls:
includePaths:
excludePaths:
authentication:
method: "client"
parameters:
script: /path/to/authentication.zst # String, the path to the Zest login script
scriptEngine: Mozilla Zest # The script engine used for the login script
diagnostics: true # Bool, enables the recording of diagnostic data during the authentication. Default: false.
minWaitFor: 5000 # Int, sets the minimum waitFor time in seconds to wait for each client statement, default: 0
verification:
method: poll
loggedOutRegex: HTTP/1.1 401
loggedInRegex: 200 OK
pollFrequency: 100
pollUnits: requests
sessionManagement:
method: headers
parameters:
Cookie: session_id={%script:myvar%}
users:
- name: 'myUser'
credentials:
username: 'myUser'
password: mypassword
proxy:
hostname: my_proxy_host
port: my_proxy_port
jobs:
- type: activeScan-config
parameters:
maxRuleDurationInMins: 0
maxScanDurationInMins: 0
maxAlertsPerRule: 0
handleAntiCSRFTokens: true
injectPluginIdInHeader: true
threadPerHost: 12
inputVectors:
urlQueryStringAndDataDrivenNodes:
odata: true
enabled: true
postData:
multiPartFormData: true
enabled: true
xml: true
directWebRemoting: true
json:
scanNullValues: true
enabled: true
googleWebToolkit: true
urlPath: true
httpHeaders:
allRequests: true
enabled: true
cookieData:
enabled: true
encodeCookieValues: true
scripts: true
- type: script
parameters:
action: add
type: httpsender
engine: Graal.js
name: httpsender
source: path/to/httpSender.js
- type: script
parameters:
action: enable
type: httpsender
engine: Graal.js
name: httpsender
- type: script
parameters:
action: add
type: authentication
engine: Mozilla Zest
name: authentication
source: /path/to/authentication.zst
- type: spider
name: spider
parameters:
context: mycontext
user: 'myUser'
maxDuration: 0
maxDepth: 0
maxChildren: 0
acceptCookies: false
handleODataParametersVisited: false
handleParameters: IGNORE_COMPLETELY
maxParseSizeBytes: 3000
parseComments: true
parseGit: true
parseRobotsTxt: true
parseSitemapXml: true
parseSVNEntries: true
parseDsStore: true
postForm: true
processForm: true
- type: spiderClient
parameters:
context: mycontext
user: 'myUser'
maxDuration: 300
maxCrawlDepth: 10
maxChildren: 50
numberOfBrowsers: 2
browserId: chrome
scopeCheck: Flexible
pageLoadTime: 5000

- parameters:
maxDuration: 0
type: passiveScan-wait

- name: activeScan
type: activeScan
parameters:
context: mycontext
policy: Default Policy
user: 'myUser'
maxRuleDurationInMins: 0
maxScanDurationInMins: 0
threadPerHost: 12
handleAntiCSRFTokens: true
injectPluginIdInHeader: true
scanHeadersAllRequests: true
policyDefinition:
defaultStrength: MEDIUM
defaultThreshold: MEDIUM
- type: report
name: report-traditional-pdf
parameters:
reportFile: report.pdf
reportDescription: This report contains the results of a vulnerability scan for
the application:https://test_url.com
reportTitle: ZAP scan report
reportDir: path/to/report
displayReport: false
template: traditional-pdf
risks:
- info
- low
- medium
- high
confidences:
- low
- medium
- high
- confirmed
sections:
- alertcount
- instancecount
- alertdetails



Can you help me figure out what went wrong please ? I can't seem to understand why the clientSpider is not authenticating.
Thank you !


thc202

unread,
Apr 20, 2026, 4:34:08 AMApr 20
to zaprox...@googlegroups.com
Hi,

Can you share the zap.log? I tried that plan (with dummy scripts/target)
and the client auth was being performed on the client spider.

Best regards.

On 17/04/2026 15:43, 'MERIEM MELLOUS' via ZAP User Group wrote:
> Hello , I noticed that when launching the following AF, the *spider does
> consider my authentication Zest script but when it comes to clientSpider
> it doesn't authenticate*. I made sure that my authentication *config in the
> env is "client" authentication* as I saw in the documentation that normally

THOMAS CROGUENNEC

unread,
Apr 21, 2026, 9:20:27 AMApr 21
to ZAP User Group
Hello,

I work with @Meriem. @thc202, I agree that the client auth works well but the problem is similar to this thread (https://groups.google.com/g/zaproxy-users/c/nn9nZ40yyIg/m/33smKLKoBQAJ). The auth is successfully done but the session management does not work as we expect. We store the token in a global script var at the end of the authentication script but when the client spider crawls, it does it unauthenticated.

Regards,

Ce message et toutes les pièces jointes (ci-après le "message") sont confidentiels et établis à l'intention exclusive de ses destinataires. Toute utilisation ou diffusion non autorisée est interdite. Tout message étant susceptible d'altération, l'émetteur décline toute responsabilité au titre de ce message s'il a été altéré, déformé ou falsifié. 
This message and any attachments (the "message") are confidential and intended solely for the addressees. Any unauthorised use or dissemination is prohibited. As e-mails are susceptible to alteration, the issuer shall not be liable for the message if altered, changed or falsified.

MERIEM MELLOUS

unread,
Apr 29, 2026, 5:11:48 AMApr 29
to ZAP User Group
Hello @thc202,

Thank you for  your response !

The issue is related to my Zest script. In fact, In my automation plan I set loginUrl , username and password as GlobalScriptVars and I add and run  the standalone Graal.js script beofre adding the authentication script. 

jobs:
- type: script
parameters:
action: "add"
context: mycontext
type: "standalone"
engine: "ECMAScript : Graal.js"
name: "setGlobalVars"
inline: |
var ScriptVars = Java.type("org.zaproxy.zap.extension.script.ScriptVars");
ScriptVars.setGlobalVar("test.loginUrl","https://test_url.com");
ScriptVars.setGlobalVar("test.username","myUser");
ScriptVars.setGlobalVar("test.password","mypassword");
- type: script
parameters:
action: "run"
context: mycontext
type: "standalone"
name: "setGlobalVars"

In my Zest script I use ZestAssignGlobalVariable in order to replace the value of the GlobalVar in a local variable so that I can automatically request the loginUrl. Yet my Zest script doesn't seem to replace the the value of the loginUrl. All scripts are running in the same context.  
  
{
"globalVariableName": "test.loginUrl",
"variableName": "loginUrl",
"index": 2,
"enabled": true,
"elementType": "ZestAssignGlobalVariable"
},
{
"windowHandle": "windowHandle1",
"browserType": "chrome",
"url": "{{loginUrl}}",
"capabilities": "window-size\u003D1200,800\n",
"headless": false,
"profilePath": "",
"index": 3,
"enabled": true,
"elementType": "ZestClientLaunch"
}

The error is:

An error occurred while trying to execute the Client Script Authentication script: invalid argument
(Session info: chrome=147.0.7727.116)
Build info: version: '4.43.0', revision: 'dd0f534'
Driver info: org.openqa.selenium.chrome.ChromeDriver
Command: [dd132c8361d6f173332c08b099f8eb4f, get {url={{loginUrl}}}]
Capabilities {acceptInsecureCerts: true, browserName: chrome, browserVersion: 147.0.7727.116, chrome: {chromedriverVersion: 147.0.7727.137 (68ba233a543..., userDataDir:
/tmp/org.chromium.Chromium....}, fedcm:accounts: true, goog:processID: 665979, networkConnectionEnabled: false, pageLoadStrategy: normal, platformName:
linux, proxy: Proxy(manual, http=127.0.0...., setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000},
unhandledPromptBehavior: dismiss and notify, webSocketUrl: ws://localhost:30265/sessio..., webauthn:extension:credBlob: true, webauthn:extension:largeBlob: true,
webauthn:extension:minPinLength: true, webauthn:extension:prf: true, webauthn:virtualAuthenticators: true}
Session ID: dd132c8361d6f173332c08b099f8eb4f
org.openqa.selenium.InvalidArgumentException: invalid argument
(Session info: chrome=147.0.7727.116)
Build info: version: '4.43.0', revision: 'dd0f534'
Driver info: org.openqa.selenium.chrome.ChromeDriver
Command: [dd132c8361d6f173332c08b099f8eb4f, get {url={{loginUrl}}}]
Capabilities {acceptInsecureCerts: true, browserName: chrome, browserVersion: 147.0.7727.116, chrome: {chromedriverVersion: 147.0.7727.137 (68ba233a543..., userDataDir:
/tmp/org.chromium.Chromium....}, fedcm:accounts: true, goog:processID: 665979, networkConnectionEnabled: false, pageLoadStrategy: normal, platformName: linux, proxy:
Proxy(manual, http=127.0.0...., setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior:
dismiss and notify, webSocketUrl: ws://localhost:30265/sessio..., webauthn:extension:credBlob: true, webauthn:extension:largeBlob: true, webauthn:extension:minPinLength:
true, webauthn:extension:prf: true, webauthn:virtualAuthenticators: true}
Session ID: dd132c8361d6f173332c08b099f8eb4f
at org.openqa.selenium.remote.ErrorCodec.decode(ErrorCodec.java:169)
at org.openqa.selenium.remote.codec.w3c.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:142)
at org.openqa.selenium.remote.codec.w3c.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:49)
at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:223)
at org.openqa.selenium.remote.service.DriverCommandExecutor.invokeExecute(DriverCommandExecutor.java:216)
at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:174)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:606)
at org.openqa.selenium.remote.RemoteWebDriver.get(RemoteWebDriver.java:374)
at org.zaproxy.addon.authhelper.internal.ZestAuthRunner.handleClient(ZestAuthRunner.java:78)
at org.zaproxy.zest.impl.ZestBasicRunner.runStatement(ZestBasicRunner.java:240)
at org.zaproxy.addon.authhelper.internal.ZestAuthRunner.runStatement(ZestAuthRunner.java:101)
at org.zaproxy.zest.impl.ZestBasicRunner.run(ZestBasicRunner.java:157)
at org.zaproxy.zest.impl.ZestBasicRunner.run(ZestBasicRunner.java:118)
at org.zaproxy.addon.authhelper.ClientScriptBasedAuthenticationMethodType$ClientScriptBasedAuthenticationMethod.executeZestAuthScript(ClientScriptBasedAuthenticationMethodType.java:264)
at org.zaproxy.addon.authhelper.ClientScriptBasedAuthenticationMethodType$ClientScriptBasedAuthenticationMethod.authenticate(ClientScriptBasedAuthenticationMethodType.java:287)
at org.zaproxy.addon.authhelper.internal.AuthenticationBrowserHook.browserLaunched(AuthenticationBrowserHook.java:50)
at org.zaproxy.zap.extension.selenium.ExtensionSelenium.lambda$getWebDriver$5(ExtensionSelenium.java:945)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
at java.base/java.util.Collections$SynchronizedCollection.forEach(Collections.java:2359)
at org.zaproxy.zap.extension.selenium.ExtensionSelenium.getWebDriver(ExtensionSelenium.java:942)
at org.zaproxy.zap.extension.selenium.ExtensionSelenium.getWebDriver(ExtensionSelenium.java:636)
at org.zaproxy.addon.client.spider.ClientSpider$WebDriverProcess.<init>(ClientSpider.java:830)
at org.zaproxy.addon.client.spider.ClientSpider.getWebDriverProcess(ClientSpider.java:340)
at org.zaproxy.addon.client.spider.ClientSpiderTask.runImpl(ClientSpiderTask.java:115)
at org.zaproxy.addon.client.spider.ClientSpiderTask.run(ClientSpiderTask.java:81)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614)
at java.base/java.lang.Thread.run(Thread.java:1474)

Also I am using Java 25.
Can you help me figure out the issue please ?
Is my approach correct when it comes to passing configs to Zest script?

Thank you ! 

Simon Bennetts

unread,
May 13, 2026, 12:34:03 PMMay 13
to ZAP User Group
FYI I'm not forgotten about this.
I've created a simple set of scripts where I set a global var in the JS script and read it in the Zest script.
That all works, which is a good start, but is not the case you reported.
I will keep looking at this, but have some other high priority work that I need to focus on.
If you have a set of example scripts etc which reproduce this then that would really speed things up. 
They dont have to actually login to anything, just show that the global variable is not used in Zest.

Cheers,

Simon

Simon Bennetts

unread,
May 27, 2026, 5:49:37 AM (6 days ago) May 27
to ZAP User Group
I think I have a setup like the one you described, but it works for me :)
Try this plan out - its completely self contained.

env:
  contexts:
  - name: Default Context
    urls:
    - http://www.example.com
    includePaths:
    - http://www.example.com.*

jobs:
- type: script
  parameters:
    name: testSetGlobalVar
    type: standalone
    action: add
    engine: "ECMAScript : Graal.js"
    inline: |-

      var ScriptVars = Java.type("org.zaproxy.zap.extension.script.ScriptVars");
      ScriptVars.setGlobalVar("test.loginUrl","https://example.com");
- type: script
  parameters:
    name: testSetGlobalVar
    type: standalone
    action: run
    engine: ""
    source: null
- type: script
  parameters:
    name: testLaunchBrowser
    type: standalone
    action: add
    engine: "Zest : Mozilla Zest"
    inline: |-
      {
        "about": "This is a Zest script. For more details about Zest visit https://github.com/zaproxy/zest/",
        "zestVersion": "0.3",
        "title": "testLaunchBrowser",
        "description": "A template standalone script",
        "prefix": "",
        "type": "StandAlone",
        "parameters": {
          "tokenStart": "{{",
          "tokenEnd": "}}",
          "tokens": {},
          "elementType": "ZestVariables"
        },
        "statements": [
          {
            "comment": "TODO!",
            "index": 1,
            "enabled": true,
            "elementType": "ZestComment"
          },

          {
            "globalVariableName": "test.loginUrl",
            "variableName": "loginUrl",
            "index": 2,
            "enabled": true,
            "elementType": "ZestAssignGlobalVariable"
          },
          {
            "message": "Var is {{loginUrl}}",
            "index": 3,
            "enabled": true,
            "elementType": "ZestActionPrint"
          },
          {
            "windowHandle": "wh1",
            "browserType": "firefox",
            "url": "{{loginUrl}}",
            "capabilities": "",
            "headless": false,
            "index": 4,
            "enabled": true,
            "elementType": "ZestClientLaunch"
          }
        ],
        "authentication": [],
        "options": {},
        "index": 0,
        "enabled": true,
        "elementType": "ZestScript"
      }
- type: script
  parameters:
    name: testLaunchBrowser
    type: standalone
    action: run
    engine: ""
    source: null


Reply all
Reply to author
Forward
0 new messages