Audit Log¶
Stentor automatically records all operator actions in a persistent audit trail. Every authenticated API request that succeeds (HTTP status < 400) is logged with operator identity, action, target, and client IP. Sensitive operations (credential access, shell commands, file transfers) are enriched with operation-specific tags.
How It Works¶
The audit middleware intercepts all authenticated API requests after the handler completes:
- Captures the operator's identity from the JWT token (user ID, email, role)
- Records the HTTP method and path as the "action" (e.g.,
POST /api/v1/cockpit/beacons/:id/shell) - Extracts target type and target ID from route parameters
- Enriches sensitive operations with operation tags (see below)
- Writes the event asynchronously (fire-and-forget, never blocks the request)
What is NOT logged
- Failed requests (HTTP status >= 400) are excluded
- Health checks (
/health) are excluded - Unauthenticated requests (no JWT) are excluded
Querying Audit Events¶
API Endpoint¶
Query Parameters¶
| Parameter | Type | Description |
|---|---|---|
operator_id | UUID | Filter by operator |
action | string | Filter by action (e.g., POST /api/v1/cockpit/beacons/:id/shell) |
target_type | string | Filter by target type (e.g., beacons, listeners) |
target_id | string | Filter by target resource ID |
since | RFC3339 | Lower time bound |
until | RFC3339 | Upper time bound |
limit | int | Max results (default 20, max 100) |
offset | int | Pagination offset |
Examples¶
Response Format¶
{
"events": [
{
"id": "a1b2c3d4-...",
"operator_id": "e5f6a7b8-...",
"operator_email": "[email protected]",
"action": "POST /api/v1/cockpit/beacons/:id/shell",
"target_type": "beacons",
"target_id": "beacon-uuid",
"details": {
"status": 200,
"query": "",
"operation": "shell_command"
},
"source_ip": "10.10.10.1",
"created_at": "2026-02-19T14:30:22Z"
}
],
"total": 245,
"limit": 20,
"offset": 0
}
Enriched Operations¶
The audit middleware tags sensitive operations with additional context in the details.operation or details.credential_op fields:
| Category | Operation Tag | Trigger |
|---|---|---|
| Shell | shell_command | Any shell command execution |
| Files | file_download, file_upload | File transfer operations |
| SSH | ssh_connect, ssh_inject, ssh_download, ssh_upload | SSH session operations |
| Credentials | hashdump, logonpasswords, mimikatz, chromedump, dcsync, keylogger | Credential harvesting commands |
| Credentials | pkinit, unpac, shadow_creds, esc_attack, acl_attack, rbcd_attack | AD credential attacks |
| Credentials | gpo_attack, dcshadow, ticket_attack, laps_dump, gmsa_dump | Domain privilege attacks |
Database Schema¶
CREATE TABLE IF NOT EXISTS audit_events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
operator_id UUID REFERENCES users(id) ON DELETE SET NULL,
operator_email VARCHAR(255) NOT NULL DEFAULT '',
action TEXT NOT NULL,
target_type TEXT NOT NULL DEFAULT '',
target_id TEXT NOT NULL DEFAULT '',
details JSONB NOT NULL DEFAULT '{}',
source_ip VARCHAR(45) NOT NULL DEFAULT '',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
Indexed for efficient querying on operator, action, target, and timestamp.