Skip to main content

hackagent.router.providers.web

The web provider — red-teams a website's chatbot by driving the live page.

This makes the live website itself the target: it keeps a real browser page open and, for every prompt the attack loop sends, types it into the chat widget, submits, and reads the assistant's reply back out of the rendered DOM. There is no endpoint reverse-engineering, request template, or response path — it interacts at the UI level the way a person does, so it works on any web chat regardless of transport (WebSocket, SSE, multipart, obfuscated URLs) and keeps auth/session/CSRF state naturally because the browser holds it. This is the general approach: point it at a URL and it just works, where HTTP capture-and-replay does not.

Reply reading is DOM-heuristics-first: after sending, it diffs the page's message elements to find the new assistant turn and waits for streamed text to settle. An optional reply_selector pins the reply element, input_selector pins the chat box, and llm_fallback_model extracts the reply via an LLM only when the heuristics come up empty.

Trade-off: a real browser round-trip per prompt is slower than an HTTP call, and calls are serialized (one shared page), so concurrent attack streams run sequentially. Like the other gap-filler providers it registers a per-instance :class:litellm.CustomLLM so requests flow through litellm.completion and the tracking logger.

Playwright ships with hackagent; the Chromium binary it drives is fetched automatically on first use.

WebAgentConfigurationError Objects

class WebAgentConfigurationError(AdapterConfigurationError)

Web-agent configuration issues (e.g. missing url / browser unavailable).

WebAgentInteractionError Objects

class WebAgentInteractionError(AdapterInteractionError)

Errors driving the live page (input not found, no reply, …).

WebAgent Objects

class WebAgent(Agent)

Adapter that red-teams a website's chatbot by driving the live page.

Required config: - url (or endpoint): the page hosting the chatbot.

Optional config: - name: label / model string (defaults to the URL host). - headless (default True): set False to watch the interaction. - timeout (page-load seconds, default 30). - wait_after_send (seconds to wait for a reply, default 20). - settle_ms (widget init wait after load, default 1500). - input_selector: CSS selector pinning the chat input box (skips the built-in input-location heuristics). - reply_selector: CSS selector pinning the reply element (skips the DOM-diff heuristic). - launcher_selector: CSS selector for the chat-launcher bubble to click open first, for widgets that start collapsed (skips the built-in launcher heuristics). - dismiss_consent (default True): accept/dismiss a cookie-consent banner on load so it can't intercept clicks on the chat launcher. - llm_fallback_model: LiteLLM model used to read the reply only when the heuristics find nothing.

probe_ready

def probe_ready() -> Optional[str]

Non-invasive reachability check for preflight.

Starts the browser session and confirms the chat input is locatable WITHOUT sending a message — so the availability probe never types a junk "healthcheck" into the live chatbot (which would contaminate the real conversation and the recorded transcript). Returns None when the widget is reachable, or an error string otherwise.

handle_request

def handle_request(request_data: Dict[str, Any]) -> Dict[str, Any]

Send a single turn to the live page via litellm.completion.