Detection · SIEM & detection

SIEM & detection stack

SecVF ships an opt-in detection stack: Loki + Promtail + Grafana for log aggregation, Suricata IDS over captured PCAPs, a YARA file scanner, and Sigma-derived alert rules. Five containers, two dashboards' worth of insight in 30 seconds. Nothing leaves your machine.

Three SecVF distributions, three different defaults:
  • Free .dmg — SIEM available; user runs docker compose up when they want it.
  • App Store $6.99 — sandbox-friendly. SIEM not bundled (Apple won't let us ship docker images via the App Store); same docker-compose works alongside.
  • SIEM Edition .dmg — same as free .dmg but the siem/ directory ships next to the app, and a Settings panel lets you start/stop the stack with one click.
See Downloads for which build is right for you.

Why a built-in SIEM

SecVF already produces SIEM-grade telemetry — every log surface is documented on the Logging & telemetry page. The raw JSONL is great for grep, terrible for "what's the trend over the last week" or "alert me when an EMERGENCY event fires." A SIEM closes that gap.

The two reasons to use it:

  • You're an analyst, not a log engineer. Pre-built dashboards, pre-wired alerts, zero configuration. Open Grafana, see signal.
  • You want detection, not just aggregation. Suricata runs against every PCAP you export, YARA scans files you drop into Quarantine, Sigma-derived alerts fire on boundary violations. The dashboards are the operational layer; the rule packs are the brain.

What's in it

ServiceImageRoleDisk
Lokigrafana/loki:3.2.1Log store + LogQL query engine~150 MB
Promtailgrafana/promtail:3.2.1Tails ~/.avf/logs/*, parses JSONL, ships to Loki~100 MB
Grafanagrafana/grafana-oss:11.3.1UI + dashboards + alerts~280 MB
Suricatajasonish/suricata:7.0.7IDS over captured PCAPs (offline mode)~250 MB
YARA scannerbuilt locally (python:3.12-slim base)Watches ~/.avf/Quarantine/, scans on file appear~120 MB

Total footprint: ~900 MB on your docker volume after first pull. ~250 MB RAM idle. The siem/ configs themselves are <500 KB; this is the image size, not the SecVF download size.

Pick a container runtime

The stack uses no Docker-only extensions — anything compose-spec compliant will run it. In rough order of preference on Apple Silicon:

RuntimeNotes
OrbStack (recommended)Built on Apple Virtualization framework — same substrate SecVF uses. ~10× lighter than Docker Desktop, faster cold start, polished UI. Free for personal use.
Docker DesktopThe default; most universal. Heavier on Mac, but if your team already has it, easiest path.
colimaCLI-only, free, lightweight. brew install colima docker docker-compose && colima start.
Rancher DesktopOpen source, GUI. Heavier than colima.
podman with podman composeWorks but slightly less common.

SecVF doesn't require OrbStack. If you already have a runtime working, use it.

Quick start

# From the SecVF repo (or the SIEM Edition .dmg payload):
cd siem/
docker compose up -d

# Watch images pull (first time: ~2 min). Subsequent starts take ~5 s.
# Then:
open http://localhost:3000

Default credentials: admin / secvf. Change the password immediately on first login (Grafana will prompt).

The SecVF dashboard folder appears in the left sidebar as soon as Grafana starts. Three dashboards are pre-loaded:

  • Severity overview — overall event volume, breakdown by severity, top subsystems, top VMs, live tail of CRITICAL+EMERGENCY events.
  • Detection — Suricata + YARA matches, timeline, top signatures, top YARA rules, live tail.
  • Containment — per-layer boundary indicators (hypervisor, network, filesystem, IPC), live tail of boundary events, response procedure embedded as a panel.

Three more ship in the SIEM Edition (Switch & capture · ISO provenance · AI sandbox sessions). They're optional and not loaded by default to keep the initial UX uncluttered.

The dashboards

Severity overview

Four severity stat panels at the top, a 5-minute-binned timeseries by severity, top subsystems and top VMs tables, then a live-tail of CRITICAL+EMERGENCY events. Updated every 30 seconds.

Reading order top-to-bottom:

  1. Stat row: EMERGENCY / CRITICAL / WARNING / INFO counts (24h). EMERGENCY is red on ≥1.
  2. Timeseries: stacked bars per severity, 5-minute bins. Useful for spotting bursts.
  3. Tables: top subsystems and top VMs by event volume. Surfaces the noisy components.
  4. Live log: raw CRITICAL+EMERGENCY events as they happen.

Detection

Combined Suricata + YARA view. Stat panels (alerts / matches / files scanned / distinct C2 indicators), detection-over-time bars, top signatures and top rules tables, live-tail of detection events.

Containment

The most important dashboard if you're doing malware analysis. Four per-layer stat panels (hypervisor, network, filesystem, IPC), a timeseries decomposing boundary events by layer, a live log of all boundary-relevant events, and an embedded markdown panel with the response procedure.

This dashboard is the operational complement to the Containment Breakout wiki page. The page is the theory; the dashboard is the live state.

Feeding data in

SecVF logs → Loki (automatic)

Promtail tails:

Host pathLoki labels
~/.avf/logs/security-*.logstream="security", plus severity, subsystem, event, vm from JSON parsing
~/.avf/logs/error-audit.logstream="error_audit", plus category, code
~/.avf/logs/network-*.logstream="network", plus src, vm
~/.avf/AISandbox/sessions/*/audit.logstream="ai_sandbox", plus severity, subsystem, event, session

No configuration needed. SecVF writes, Promtail tails, Loki ingests. Visible in Grafana within seconds.

PCAPs → Suricata

SecVF's Packet Analysis panel writes PCAPs to ~/.avf/Captures/. Suricata watches that directory and analyzes new files within ~5 seconds. Results land in /var/log/suricata/eve.json inside the container, which Promtail tails and ships to Loki under stream="suricata".

To analyze an external PCAP without going through SecVF:

cp /path/to/external.pcap ~/.avf/Captures/
# Watch the Detection dashboard — alerts appear in 5-10 seconds.

Files → YARA

Drop suspect files into ~/.avf/Quarantine/:

mkdir -p ~/.avf/Quarantine
cp /path/to/suspect.bin ~/.avf/Quarantine/

The YARA scanner picks up the file within a second, computes SHA-256, runs the full rule set with a 60-second timeout, emits one scan.done record + one scan.match record per matching rule. Results in the Detection dashboard.

The Quarantine directory is mounted read-only into the container — nothing executes there, the scanner only reads.

Alerts & notifications

Seven alert rules ship pre-provisioned in siem/grafana/provisioning/alerting/alerts.yaml:

AlertSeverityFires when
EMERGENCY event detectedcriticalany EMERGENCY in last 5 min
ISO checksum mismatchcriticalany checksum.mismatch in last 10 min
Sustained switch packet dropswarningswitch.drop events for >5 min straight
Unexpected file in VM bundlecriticalfile.unexpected in last 10 min
Suricata C2/trojan/malware trafficwarningany matching alert in last 10 min
YARA rule matchedwarningany scan.match in last 10 min
AI sandbox session orphanwarningsession.orphaned in last 10 min

To wire these up to actually notify you (email, Slack, Discord, PagerDuty, Apple system notification via a webhook):

  1. Grafana → Alerting → Contact points → Add contact point
  2. Pick your channel; for macOS-native notifications, the easiest path is a webhook to a small local script that calls osascript -e 'display notification ...'.
  3. Grafana → Alerting → Notification policies → Edit default → set your contact point
  4. Fire a test alert to confirm.

Until you add a contact point, alerts still fire internally — they show up in Grafana's Alerts panel — they just don't push anywhere external.

Customizing detection rules

Suricata

Two rule sets ship:

  • siem/suricata/rules/secvf-custom.rules — 12 SecVF-specific rules (sandbox-detect, lateral movement, host targeting, beacon shapes). MIT licensed.
  • siem/suricata/rules/et-open-*.rules — placeholder files with instructions to pull the live ET Open ruleset. The bundled set is small/illustrative; for production analysis, pull upstream.

To add more rules:

# Pull the upstream ET Open ruleset
wget https://rules.emergingthreats.net/open/suricata-7.0.7/emerging-malware.rules \
     -O siem/suricata/rules/emerging-malware.rules

# Add it to suricata.yaml under rule-files:
#   - emerging-malware.rules

docker compose restart suricata

YARA

Two rule files ship in siem/yara-scanner/rules/:

  • secvf-host-indicator.yar — high-precision rules that flag files showing awareness of the SecVF lab environment. Use this first — a match is almost always meaningful.
  • malware-loaders.yar — generic loader/beacon/shellcode rules. Medium precision.

For broader coverage, see siem/yara-scanner/rules/README.md — it documents which upstream packs are license-compatible with SecVF builds (the App Store edition has tighter licensing constraints).

Sigma

Five Sigma rules ship in siem/sigma/. They're the canonical detection sources; we pre-compile them to LogQL in the alert config. To add a Sigma rule:

# Write the Sigma rule (vendor-neutral YAML)
$EDITOR siem/sigma/secvf-my-new-rule.yml

# Compile to LogQL
python3 -m venv .venv && source .venv/bin/activate
pip install sigma-cli pysigma-backend-loki
sigma convert -t loki siem/sigma/secvf-my-new-rule.yml

# Paste the output into the matching alert rule's `expr:` field in
# siem/grafana/provisioning/alerting/alerts.yaml

docker compose restart grafana

See siem/sigma/README.md for the full pipeline notes.

Security stance

The SIEM stack is itself a piece of analyst-grade software. We take its security seriously:

  • All ports bound to 127.0.0.1. Nothing on the SIEM is reachable from outside your machine. To expose externally, you'd need to put a reverse proxy in front with authentication — out of scope for the default bundle.
  • Read-only mounts of ~/.avf/logs/, ~/.avf/AISandbox/, and ~/.avf/Captures/. The SIEM reads what SecVF writes; it cannot tamper with audit trails.
  • Dropped Linux capabilities on every container (cap_drop: [ALL]). no-new-privileges set.
  • Memory and PID limits on every service to bound damage from a compromise.
  • Telemetry disabled. Grafana's update-check, analytics, plugin-update-check are off. Loki's reporting_enabled: false.
  • Image pinning. Compose uses specific tags (3.2.1, 11.3.1), not :latest. Upgrade is a deliberate action.

Operations

# Start
cd siem/ && docker compose up -d

# Stop (keeps data)
docker compose down

# Stop + wipe everything
docker compose down -v

# Restart one service
docker compose restart suricata
docker compose restart grafana

# Tail logs
docker compose logs -f promtail
docker compose logs -f yara-scanner

# Update images (after pinning a new tag in compose.yaml)
docker compose pull
docker compose up -d

# Disk usage check
docker system df

Backups

Two things matter:

  1. Grafana dashboards you've customized. The grafana-data docker volume holds them. Back it up:
    docker run --rm -v secvf-grafana-data:/data \
      -v $(pwd):/backup alpine \
      tar -czf /backup/grafana-backup-$(date +%F).tar.gz -C /data .
  2. Loki's TSDB if you have months of logs you want to keep. Same pattern, volume is loki-data.

The configs themselves live in the SecVF repo — version controlled there.

Outside-stack integration

Ship to your enterprise SIEM (Splunk, Datadog, Elastic)

Promtail also accepts multiple downstream clients. Edit siem/promtail/promtail-config.yaml under clients::

clients:
  - url: http://loki:3100/loki/api/v1/push       # the bundled Loki
  - url: https://your-splunk-hec.example.com/... # your enterprise SIEM
    basic_auth:
      username: hec-token
      password: ...

Restart Promtail: docker compose restart promtail.

Native macOS Unified Logging bridge

Every SecVF event is also published to macOS's os_log under subsystem com.DaxxSec.SecVF. If your enterprise agent (CrowdStrike, Defender for Endpoint, etc.) ingests OSLog, you get SecVF events for free.

log stream --predicate 'subsystem == "com.DaxxSec.SecVF"' --info

Troubleshooting

SymptomLikely causeFix
Grafana shows "no data" everywherePromtail can't read SecVF logsVerify ~/.avf/logs/*.log exists; check docker compose logs promtail for permission errors
"unable to connect to loki" in Promtail logsLoki not healthy yet (slow first start)Wait 30 s; docker compose ps should show loki as healthy. If not, docker compose logs loki.
Suricata never alertsNo PCAPs in ~/.avf/Captures/ yetExport a capture from SecVF's Packet Analysis panel, OR drop a known-bad PCAP for testing.
YARA scanner shows "no rules found"yara-scanner/rules/ is emptyAdd .yar files; docker compose restart yara-scanner
Port 3000 conflictsAnother Grafana already thereEdit ports: in compose: 127.0.0.1:3001:3000
"docker: command not found"No container runtime installedSee Pick a container runtime
Containers consume all memoryLoki retention too long, logs hugeLower retention_period in loki-config.yaml (default 720h = 30d)
OrbStack doesn't startApple Silicon required for full functionalityOrbStack is Apple-Silicon-only. On Intel Macs, use Docker Desktop or colima.
Alerts fire but no notificationNo contact point configuredSee Alerts & notifications; default is silent.