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.
- Free .dmg — SIEM available; user runs
docker compose upwhen 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.
On this page
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
| Service | Image | Role | Disk |
|---|---|---|---|
| Loki | grafana/loki:3.2.1 | Log store + LogQL query engine | ~150 MB |
| Promtail | grafana/promtail:3.2.1 | Tails ~/.avf/logs/*, parses JSONL, ships to Loki | ~100 MB |
| Grafana | grafana/grafana-oss:11.3.1 | UI + dashboards + alerts | ~280 MB |
| Suricata | jasonish/suricata:7.0.7 | IDS over captured PCAPs (offline mode) | ~250 MB |
| YARA scanner | built 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:
| Runtime | Notes |
|---|---|
| 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 Desktop | The default; most universal. Heavier on Mac, but if your team already has it, easiest path. |
| colima | CLI-only, free, lightweight. brew install colima docker docker-compose && colima start. |
| Rancher Desktop | Open source, GUI. Heavier than colima. |
podman with podman compose | Works 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:
- Stat row: EMERGENCY / CRITICAL / WARNING / INFO counts (24h). EMERGENCY is red on ≥1.
- Timeseries: stacked bars per severity, 5-minute bins. Useful for spotting bursts.
- Tables: top subsystems and top VMs by event volume. Surfaces the noisy components.
- 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 path | Loki labels |
|---|---|
~/.avf/logs/security-*.log | stream="security", plus severity, subsystem, event, vm from JSON parsing |
~/.avf/logs/error-audit.log | stream="error_audit", plus category, code |
~/.avf/logs/network-*.log | stream="network", plus src, vm |
~/.avf/AISandbox/sessions/*/audit.log | stream="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:
| Alert | Severity | Fires when |
|---|---|---|
| EMERGENCY event detected | critical | any EMERGENCY in last 5 min |
| ISO checksum mismatch | critical | any checksum.mismatch in last 10 min |
| Sustained switch packet drops | warning | switch.drop events for >5 min straight |
| Unexpected file in VM bundle | critical | file.unexpected in last 10 min |
| Suricata C2/trojan/malware traffic | warning | any matching alert in last 10 min |
| YARA rule matched | warning | any scan.match in last 10 min |
| AI sandbox session orphan | warning | session.orphaned in last 10 min |
To wire these up to actually notify you (email, Slack, Discord, PagerDuty, Apple system notification via a webhook):
- Grafana → Alerting → Contact points → Add contact point
- Pick your channel; for macOS-native notifications, the easiest path is a webhook to a small local script that calls
osascript -e 'display notification ...'. - Grafana → Alerting → Notification policies → Edit default → set your contact point
- 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-privilegesset. - 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:
- Grafana dashboards you've customized. The
grafana-datadocker 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 . - 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
| Symptom | Likely cause | Fix |
|---|---|---|
| Grafana shows "no data" everywhere | Promtail can't read SecVF logs | Verify ~/.avf/logs/*.log exists; check docker compose logs promtail for permission errors |
| "unable to connect to loki" in Promtail logs | Loki 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 alerts | No PCAPs in ~/.avf/Captures/ yet | Export 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 empty | Add .yar files; docker compose restart yara-scanner |
| Port 3000 conflicts | Another Grafana already there | Edit ports: in compose: 127.0.0.1:3001:3000 |
| "docker: command not found" | No container runtime installed | See Pick a container runtime |
| Containers consume all memory | Loki retention too long, logs huge | Lower retention_period in loki-config.yaml (default 720h = 30d) |
| OrbStack doesn't start | Apple Silicon required for full functionality | OrbStack is Apple-Silicon-only. On Intel Macs, use Docker Desktop or colima. |
| Alerts fire but no notification | No contact point configured | See Alerts & notifications; default is silent. |