TantoC2 uses Flask-SocketIO for real-time event push to authenticated clients.
Connecting
#Connect via Socket.IO with a valid access token:
1
2
3
| const socket = io("http://localhost:8443", {
auth: { token: "<access_token>" }
});
|
Events are emitted server-wide to all authenticated clients connected to the same engagement.
Event Catalog
#Agent Events
#| Event | Data | Trigger |
|---|
agent_registered | {agent_id, package} | New agent registers |
agent_checkin | {agent_id} | Agent checks in |
agent_killed | {agent_id} | Kill command sent |
agent_status_changed | {agent_id, status} | Agent transitions to dormant or dead. Session agents transition directly to dead on transport disconnect (skipping dormant). |
Task Events
#| Event | Data | Trigger |
|---|
task_completed | {task_id, agent_id} | Agent returns final task result |
task_streaming_result | {task_id, agent_id} | Agent returns intermediate result from long-running module |
module_execution_started | {task_id, module_name, agent_id} | Module queued |
Shell Events
#| Event | Data | Trigger |
|---|
agent_shell_open | {session_id, agent_id} | Agent shell session opened |
agent_shell_output | {session_id, data} | Output from an agent shell session |
agent_shell_close | {session_id} | Agent shell session closed |
tools_shell_open | {session_id, module_name} | Tools shell session opened |
tools_shell_output | {session_id, data} | Output from a tools shell session |
tools_shell_close | {session_id} | Tools shell session closed |
session_output | {session_id, data} | Interactive tools session output (legacy agentless sessions) |
Build and Transfer Events
#| Event | Data | Trigger |
|---|
build_completed | {build_id, package_name, template_name, binary_hash} | Build finishes |
file_transfer_initiated | {transfer_id, agent_id, direction, remote_path} | Transfer starts |
file_transfer_completed | {transfer_id, agent_id} | Transfer finishes |
Tools Events
#| Event | Data | Trigger |
|---|
agentless_execution_started | {execution_id, module_name, operation} | Tools operation begins |
agentless_execution_completed | {execution_id} | Tools operation finishes |
Infrastructure Events
#| Event | Data | Trigger |
|---|
p2p_link_created | {relay_agent_id, interior_agent_id} | P2P relay link established |
plugins_refreshed | {new_plugins, counts} | Plugin load/upload/refresh completes |
security_alert | {event_type, details} | Security-flagged event |
Usage in Python Client
#1
2
3
4
5
6
7
| from tantoc2.client import TantoC2Client
client = TantoC2Client("http://localhost:8443")
client.login("admin", "<password>")
client.on_event("agent_registered", lambda data: print(f"New agent: {data['agent_id']}"))
client.on_event("task_completed", lambda data: print(f"Result: {data['task_id']}"))
|
Shell Event Flow
#The agent terminal in the Web UI and the tools shell both use WebSocket events for real-time I/O. The flow is:
- Client calls
POST /api/v1/shell/agent or POST /api/v1/shell/tools to open a session - Server emits
agent_shell_open or tools_shell_open with a session_id - Client sends input via
POST /api/v1/shell/agent/input or tools/input - Server emits
agent_shell_output or tools_shell_output as output is produced - Client calls
POST /api/v1/shell/agent/close or tools/close to end the session - Server emits
agent_shell_close or tools_shell_close
All output events and close events are broadcast to all authenticated clients in the same engagement — any operator viewing the terminal sees the same stream.
Session Disconnect Events
#When a TCP transport session disconnects, the server fires an agent_status_changed event with status: "dead" immediately, without waiting for the dormant threshold. This provides instant feedback in the Web UI (“Disconnected” badge) rather than waiting for the dead agent background scanner.
Security Events
#The security_alert event is emitted for security-flagged audit entries:
- Failed login attempts
- Force-logout operations
- Token revocations
These appear with visual emphasis in both the CLI event stream and the Web UI audit log.