Skip to content

Commit d1e434f

Browse files
committed
Add WebSocket generator for real-time LLM security testing (#1379)
2 parents f51e7db + 9ac5128 commit d1e434f

File tree

7 files changed

+1015
-1
lines changed

7 files changed

+1015
-1
lines changed
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
garak.generators.websocket
2+
==========================
3+
4+
WebSocket connector for real-time LLM services.
5+
6+
This generator enables garak to test WebSocket-based LLM services that use
7+
real-time bidirectional communication, similar to modern chat applications.
8+
9+
Uses the following options from ``_config.plugins.generators["websocket"]["WebSocketGenerator"]``:
10+
11+
* ``uri`` - the WebSocket URI (ws:// or wss://); can also be passed in --model_name
12+
* ``name`` - a short name for this service; defaults to "WebSocket Generator"
13+
* ``auth_type`` - authentication method: "none", "basic", "bearer", or "custom"
14+
* ``username`` - username for basic authentication
15+
* ``api_key`` - API key for bearer token auth or password for basic auth
16+
* ``key_env_var`` - environment variable holding API key; default ``WEBSOCKET_API_KEY``
17+
* ``req_template`` - string template where ``$INPUT`` is replaced by prompt, ``$KEY`` by API key, ``$CONVERSATION_ID`` by conversation ID
18+
* ``req_template_json_object`` - request template as Python object, serialized to JSON with placeholder replacements
19+
* ``headers`` - dict of additional WebSocket headers
20+
* ``response_json`` - is the response in JSON format? Set to ``True`` if the WebSocket returns JSON responses that need parsing (bool, default: ``False``)
21+
* ``response_json_field`` - which field in the JSON response contains the actual text to extract? Supports simple field names like ``"text"`` or JSONPath notation like ``"$.data.message"`` for nested fields (str, default: ``"text"``)
22+
* ``response_after_typing`` - wait for typing indicators to complete before returning response? Set to ``True`` for services that send typing notifications, ``False`` to return the first message immediately (bool, default: ``True``)
23+
* ``typing_indicator`` - substring to detect in messages that indicates the service is still typing; messages containing this string are filtered out when ``response_after_typing`` is ``True`` (str, default: ``"typing"``)
24+
* ``request_timeout`` - seconds to wait for response; default 20
25+
* ``connection_timeout`` - seconds to wait for connection; default 10
26+
* ``max_response_length`` - maximum response length; default 10000
27+
* ``verify_ssl`` - enforce SSL certificate validation? Default ``True``
28+
29+
Templates work similarly to the REST generator. The ``$INPUT``, ``$KEY``, and
30+
``$CONVERSATION_ID`` placeholders are replaced in both string templates and
31+
JSON object templates.
32+
33+
JSON Response Extraction
34+
------------------------
35+
36+
The ``response_json_field`` parameter supports JSONPath-style extraction:
37+
38+
* Simple field: ``"text"`` extracts ``response.text``
39+
* Nested field: ``"$.data.message"`` extracts ``response.data.message``
40+
* Array access: ``"$.messages[0].content"`` extracts first message content
41+
42+
Authentication Methods
43+
----------------------
44+
45+
**No Authentication:**
46+
47+
.. code-block:: JSON
48+
49+
{
50+
"websocket": {
51+
"WebSocketGenerator": {
52+
"uri": "ws://localhost:3000/chat",
53+
"auth_type": "none"
54+
}
55+
}
56+
}
57+
58+
**Basic Authentication:**
59+
60+
.. code-block:: JSON
61+
62+
{
63+
"websocket": {
64+
"WebSocketGenerator": {
65+
"uri": "ws://localhost:3000/chat",
66+
"auth_type": "basic",
67+
"username": "user"
68+
}
69+
}
70+
}
71+
72+
Set the password via environment variable:
73+
74+
.. code-block:: bash
75+
76+
export WEBSOCKET_API_KEY="your_secure_password"
77+
78+
**Bearer Token:**
79+
80+
.. code-block:: JSON
81+
82+
{
83+
"websocket": {
84+
"WebSocketGenerator": {
85+
"uri": "wss://api.example.com/llm",
86+
"auth_type": "bearer",
87+
"api_key": "your_api_key_here"
88+
}
89+
}
90+
}
91+
92+
**Environment Variable API Key:**
93+
94+
.. code-block:: JSON
95+
96+
{
97+
"websocket": {
98+
"WebSocketGenerator": {
99+
"uri": "wss://api.example.com/llm",
100+
"auth_type": "bearer",
101+
"key_env_var": "MY_LLM_API_KEY"
102+
}
103+
}
104+
}
105+
106+
Message Templates
107+
-----------------
108+
109+
**Simple Text Template:**
110+
111+
.. code-block:: JSON
112+
113+
{
114+
"websocket": {
115+
"WebSocketGenerator": {
116+
"uri": "ws://localhost:3000/chat",
117+
"req_template": "User: $INPUT"
118+
}
119+
}
120+
}
121+
122+
**JSON Object Template:**
123+
124+
.. code-block:: JSON
125+
126+
{
127+
"websocket": {
128+
"WebSocketGenerator": {
129+
"uri": "ws://localhost:3000/chat",
130+
"req_template_json_object": {
131+
"message": "$INPUT",
132+
"conversation_id": "$CONVERSATION_ID",
133+
"api_key": "$KEY"
134+
},
135+
"response_json": true,
136+
"response_json_field": "text"
137+
}
138+
}
139+
}
140+
141+
**Complex JSON with Nested Response:**
142+
143+
.. code-block:: JSON
144+
145+
{
146+
"websocket": {
147+
"WebSocketGenerator": {
148+
"uri": "wss://api.example.com/llm",
149+
"req_template_json_object": {
150+
"prompt": "$INPUT",
151+
"stream": false,
152+
"model": "gpt-4"
153+
},
154+
"response_json": true,
155+
"response_json_field": "$.choices[0].message.content"
156+
}
157+
}
158+
}
159+
160+
Usage Examples
161+
---------------
162+
163+
**Command Line with JSON Options:**
164+
165+
.. code-block:: bash
166+
167+
# Set password securely via environment variable
168+
export WEBSOCKET_API_KEY="your_secure_password"
169+
170+
garak --model_type websocket.WebSocketGenerator \
171+
--generator_options '{"websocket": {"WebSocketGenerator": {"uri": "ws://localhost:3000", "auth_type": "basic", "username": "user"}}}' \
172+
--probes dan
173+
174+
**Configuration File:**
175+
176+
Save configuration to ``websocket_config.json`` and use:
177+
178+
.. code-block:: bash
179+
180+
garak --model_type websocket.WebSocketGenerator \
181+
-G websocket_config.json \
182+
--probes encoding
183+
184+
**Testing with Public Echo Server:**
185+
186+
.. code-block:: bash
187+
188+
garak --model_type websocket.WebSocketGenerator \
189+
--generator_options '{"websocket": {"WebSocketGenerator": {"uri": "wss://echo.websocket.org", "response_after_typing": false}}}' \
190+
--probes dan --generations 1
191+
192+
SSH Tunnel Support
193+
------------------
194+
195+
The generator works seamlessly with SSH tunnels for secure remote testing:
196+
197+
.. code-block:: bash
198+
199+
# Establish tunnel
200+
ssh -L 3000:target-host:3000 jump-host -N -f
201+
202+
# Test through tunnel
203+
garak --model_type websocket.WebSocketGenerator \
204+
--generator_options '{"websocket": {"WebSocketGenerator": {"uri": "ws://localhost:3000"}}}' \
205+
--probes malwaregen
206+
207+
Typing Indicators
208+
-----------------
209+
210+
Many chat-based LLMs send typing indicators. Configure response handling:
211+
212+
* ``response_after_typing: true`` - Wait for typing to complete (default)
213+
* ``response_after_typing: false`` - Return first substantial response
214+
* ``typing_indicator`` - String to detect typing status (default "typing")
215+
216+
This enables proper testing of streaming/real-time LLM services.
217+
218+
----
219+
220+
.. automodule:: garak.generators.websocket
221+
:members:
222+
:undoc-members:
223+
:show-inheritance:
224+
225+

docs/source/generators.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,4 @@ For a detailed oversight into how a generator operates, see :doc:`garak.generato
3232
garak.generators.rasa
3333
garak.generators.test
3434
garak.generators.watsonx
35+
garak.generators.websocket

0 commit comments

Comments
 (0)