Scanning Browser-Based Agents¶
This guide walks through scanning an AI agent that only exposes a web chat UI.
Installation¶
pip install ziran[browser]
playwright install chromium
Step 1: Create a Target Config¶
Create a YAML file describing how to interact with the chat UI:
# target.yaml
url: https://chatbot.example.com/chat
protocol: browser
browser:
input_selector: "textarea"
submit_selector: "button[type='submit']"
response_selector: ".assistant-message"
Finding CSS Selectors¶
Open the chatbot in your browser and use DevTools (F12) to inspect:
- Input selector: Right-click the text input, "Inspect", and note the
textareaorinputelement - Submit selector: Right-click the send button and note its selector
- Response selector: Right-click an assistant response bubble and note the common class
Auto-Detection¶
If you omit api_url_pattern, ZIRAN sends a probe message and monitors which API endpoints the UI calls. For most standard chat UIs, auto-detection works well:
url: https://chatbot.example.com/chat
protocol: browser
Smart UI Discovery¶
ZIRAN automatically handles chatbot UIs that require interaction before the chat input appears:
- Cookie banners: Automatically dismissed (prefers "Reject" for privacy)
- Chat launcher buttons: Clicks "Start Chat", "Open Chat", and similar buttons
- Hidden inputs: Probes for
textarea,input,contenteditable, and[role='textbox']elements - Submit buttons: Discovers send/submit buttons near the input
This means a minimal config often works even for complex chat widgets:
url: https://example.com/chatbot/
protocol: browser
To disable auto-discovery (e.g., if it interferes with a specific UI):
browser:
auto_discover: false
input_selector: "#chat-input"
Option / Quick-Reply Menus¶
Many chatbots present clickable options ("Track package", "Report issue") instead of accepting free text immediately. ZIRAN handles this automatically:
browser:
initial_options: auto # auto (default), click_through, type_through, skip
max_option_depth: 3 # how many menu levels to navigate
option_selector: "" # custom selector for option buttons (empty = auto-detect)
prefer_options: # option texts to prefer (tried first, case-insensitive)
- "Vraag stellen"
- "Ask a question"
Strategies:
auto(default) — Looks for "Something else" / "Other" options first, then clicks the first optionclick_through— Clicks the first option at each leveltype_through— Ignores options and types directly (works if the bot accepts free text)skip— Does nothing about options
The prefer_options list is checked before all built-in patterns. Use it when you know which option leads to the LLM-powered free-text mode in a hybrid bot. Matches are case-insensitive substrings.
Step 2: Run the Scan¶
# Standard scan
ziran scan --target target.yaml
# Essential coverage only (faster)
ziran scan --target target.yaml --coverage essential
# Force browser protocol
ziran scan --target target.yaml --protocol browser
Step 3: Review Results¶
Reports are generated in the same formats as all ZIRAN scans:
open ziran_results/campaign_*_report.html
Login Flows¶
For agents behind authentication:
url: https://agent.example.com/chat
protocol: browser
browser:
login_url: https://agent.example.com/login
login_steps:
- selector: "#email"
action: fill
value: "${AGENT_EMAIL}"
- selector: "#password"
action: fill
value: "${AGENT_PASSWORD}"
- selector: "button[type='submit']"
action: click
input_selector: "#chat-input"
response_selector: ".bot-response"
Environment variables in ${VAR} syntax are resolved at runtime.
Timing Configuration¶
Adjust timeouts for slow-responding agents:
browser:
navigation_timeout: 30.0 # Page load timeout (seconds)
response_timeout: 90.0 # Wait for agent response (seconds)
settle_delay: 2.0 # Wait after last DOM change (seconds)
WebSocket-Based Chatbots¶
Chatbots that use WebSocket (e.g., Cognigy.AI, Socket.IO-based platforms) are supported automatically. ZIRAN detects WebSocket connections during the probe phase and captures incoming frames.
For explicit configuration:
browser:
websocket_url_pattern: "**/socket.io/**" # URL pattern to match (empty = all)
websocket_event_name: "output" # Socket.IO event to capture
websocket_message_path: "data.text" # JSON path to bot response text
Cognigy.AI Example¶
url: https://webchat-postnl-service-dev.cognigy.cloud/v3/YOUR_TOKEN
protocol: browser
browser:
headless: false
response_timeout: 90.0
settle_delay: 3.0
websocket_event_name: "output"
websocket_message_path: "data.text"
WebSocket capture also logs outgoing messages, fixing the prompt_used: null issue in scan reports.
Troubleshooting¶
No response detected¶
- Increase
response_timeoutandsettle_delay - Check
response_selectormatches the actual DOM elements - For WebSocket chatbots: check
websocket_event_nameandwebsocket_message_path - Run with
--verboseto see detailed logs
Wrong API endpoint detected¶
- Set
api_url_patternexplicitly (e.g.,"**/api/chat/**") - Set
response_json_pathto the correct field path
Login fails¶
- Test selectors manually in the browser DevTools console
- Ensure environment variables are set for
${VAR}references - Check
login_urlis correct
Auto-discovery clicks the wrong button¶
If ZIRAN clicks the wrong element during UI discovery, disable it:
browser:
auto_discover: false
input_selector: "textarea"
submit_selector: "button[type='submit']"
Non-headless debugging¶
Set headless: false in the browser config to see the browser:
browser:
headless: false