Skip to content

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:

  1. Captures the operator's identity from the JWT token (user ID, email, role)
  2. Records the HTTP method and path as the "action" (e.g., POST /api/v1/cockpit/beacons/:id/shell)
  3. Extracts target type and target ID from route parameters
  4. Enriches sensitive operations with operation tags (see below)
  5. 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

GET /api/v1/audit/events

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

curl -s "https://stentor.app/api/v1/audit/events?limit=10" \
  -H "Authorization: Bearer $TOKEN" | jq
curl -s "https://stentor.app/api/v1/audit/events?operator_id=OPERATOR_UUID&limit=50" \
  -H "Authorization: Bearer $TOKEN" | jq
curl -s "https://stentor.app/api/v1/audit/events?action=POST+/api/v1/c2/beacons/:id/hashdump" \
  -H "Authorization: Bearer $TOKEN" | jq
curl -s "https://stentor.app/api/v1/audit/events?since=2026-02-19T00:00:00Z&until=2026-02-19T23:59:59Z" \
  -H "Authorization: Bearer $TOKEN" | jq

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.