Skip to content

Team Chat

Stentor includes a built-in real-time chat system for operator coordination during engagements. Messages are delivered instantly via the CockpitHub WebSocket, appearing in the Event Log tab alongside beacon events and system notifications. The chat supports public messages, private messages, action messages, and operator presence queries.


Architecture

Chat messages flow through the REST API to the CockpitHub WebSocket, which broadcasts them to connected operator clients in real time. There is no persistent message storage -- chat is ephemeral and scoped to the current session.

sequenceDiagram
    participant Op1 as Operator A
    participant API as REST API
    participant Hub as CockpitHub<br/>(WebSocket)
    participant Op2 as Operator B
    participant Op3 as Operator C

    Op1->>API: POST /cockpit/chat<br/>{"message": "Got DA creds"}
    API->>Hub: BroadcastConsoleLog
    Hub-->>Op1: console_log event
    Hub-->>Op2: console_log event
    Hub-->>Op3: console_log event

Sending Messages

All chat messages are sent via the same endpoint. The message content determines whether it is a public broadcast, private message, action, or query.

Public Message

A regular chat message broadcast to all connected operators.

curl -s -X POST https://stentor.app/api/v1/cockpit/chat \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Starting lateral movement to DC01"
  }' | jq
{
  "status": "sent"
}

All connected operators receive a WebSocket event:

{
  "type": "console_log",
  "payload": {
    "tab_id": "event-log",
    "timestamp": "14:30:05",
    "type": "chat",
    "text": "<[email protected]> Starting lateral movement to DC01"
  }
}

Private Message

Send a message visible only to a specific operator using the /msg command prefix.

curl -s -X POST https://stentor.app/api/v1/cockpit/chat \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "/msg [email protected] Check the creds I just dumped"
  }' | jq
{
  "status": "sent"
}
{
  "error": "operator \"[email protected]\" not connected"
}

The private message is delivered to both the sender and the recipient. Other connected operators do not see it.

Format: /msg <recipient-email> <message text>

Recipient must be connected

Private messages can only be delivered to operators with an active WebSocket connection. If the recipient is not connected, the API returns a 404 error.


Action Message

Send an action message (similar to IRC /me) that displays as a status line rather than a chat bubble.

curl -s -X POST https://stentor.app/api/v1/cockpit/chat \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "/me is escalating privileges on WS01"
  }' | jq
{
  "status": "sent"
}

All connected operators receive:

{
  "type": "console_log",
  "payload": {
    "tab_id": "event-log",
    "timestamp": "14:32:10",
    "type": "info",
    "text": "*** [email protected] is escalating privileges on WS01"
  }
}

Format: /me <action text>


List Connected Operators

Query the list of currently connected operators. This message is only sent back to the requesting operator -- it is not broadcast.

curl -s -X POST https://stentor.app/api/v1/cockpit/chat \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "/names"
  }' | jq
{
  "status": "sent"
}

The requesting operator receives a private console log entry:

{
  "type": "console_log",
  "payload": {
    "tab_id": "event-log",
    "timestamp": "14:33:00",
    "type": "info",
    "text": "Connected operators: [email protected], [email protected]"
  }
}

Chat Commands Summary

Command Syntax Visibility Description
Public <message> All operators Broadcast to everyone
Private /msg <email> <text> Sender + recipient Direct message to one operator
Action /me <text> All operators Status/action message
Names /names Sender only List connected operators

Operator Presence

List Connected Operators (REST)

Query the list of currently connected operator emails via a dedicated REST endpoint, independent of the chat system.

curl -s https://stentor.app/api/v1/cockpit/operators \
  -H "Authorization: Bearer $TOKEN" | jq
{
  "operators": [
    "[email protected]",
    "[email protected]",
    "[email protected]"
  ],
  "count": 3
}

Response fields:

Field Type Description
operators string[] Email addresses of connected operators
count int Number of connected operators

Automatic polling

The Stentor UI polls the operators endpoint every 15 seconds to keep the connected operators list current.


WebSocket Integration

Chat messages are delivered through the CockpitHub WebSocket at /api/v1/cockpit/ws. This is the same WebSocket used for beacon updates, task completions, and other real-time events. Chat messages are distinguished by their event structure:

Field Value Description
type console_log Event type (same as shell output and system messages)
payload.tab_id event-log Always delivered to the Event Log tab
payload.type chat or info chat for public/private messages, info for actions and /names
payload.timestamp HH:MM:SS Server-side timestamp when the message was processed
payload.text string Formatted message text

Message text formats:

Chat Type Text Format
Public <sender@email> message text
Private [private] <sender@email -> recipient@email> message text
Action *** sender@email action text
Names Connected operators: email1, email2, ...

Event Log Tab

Chat messages appear in the Event Log tab in the cockpit console alongside other operational events (beacon check-ins, task completions, errors). This unified timeline gives operators a chronological view of both system activity and team communication.

The Event Log is the default tab and is always available. Chat messages are interleaved with:

  • Beacon registration and check-in notifications
  • Task queuing and completion events
  • Listener start/stop notifications
  • System errors and warnings

Dedicated chat input

The cockpit console input can be used for both beacon shell commands (when a beacon tab is active) and chat messages (when the Event Log tab is active). Switch to the Event Log tab to type chat messages.


API Summary

Method Endpoint Description
POST /api/v1/cockpit/chat Send a chat message (public, private, action, or names query)
GET /api/v1/cockpit/operators List currently connected operators
GET /api/v1/cockpit/ws WebSocket endpoint for real-time events (including chat delivery)