Local-first AI alert triage for Suricata and Wazuh. Reduce security noise without sending telemetry to the cloud.
Get started · Documentation · Latest release
99%+ typical policy resolution after tuning · 100% local with no alert telemetry · 266-alert approved release evaluation
Suricata and Wazuh are excellent sensors, but high-volume alerts still leave an operator with a prioritization problem. TriageWall adds a local decision layer: validated deterministic policy handles known repeat noise, a local security model reviews the long tail, and a source-aware workbench keeps the final decision with the operator.
TriageWall is built for self-hosted security teams, homelab operators, and small environments that want useful triage without uploading alert evidence to a cloud model. It reads from your sensors and records decisions; it does not block traffic, change sensor rules, or take autonomous response actions.
- One review queue for Suricata and Wazuh. Preserve source, event, rule, agent, and network context instead of flattening every sensor into one shape.
- Two-tier local classification. Resolve carefully scoped repeat noise in microseconds and send only the residual long tail to a local Ollama model.
- Analyst investigation views. Review recurrence, related activity, source-specific evidence, and queue-aware Previous/Next navigation.
- Bounded alert search. Find retained alerts by signature, exact IP address, or historical asset hostname without allowing an absent term to scan an unbounded production database.
- Versioned operator configuration. Draft, validate, preview, activate, and roll back prefilter and private asset revisions with optimistic locking, attribution, and audit history.
- Evidence-driven releases. Regression CI, CodeQL, deterministic gold-set gates, documented threat boundaries, and production release evidence are part of the release process.
The 20-second demo uses sanitized fixture data from v0.4. Addresses are masked, feedback is disabled, and no production telemetry is shown.
| Signal | Measured result | Scope |
|---|---|---|
| Deterministic policy resolution | 99%+ typical after site tuning | Production-shaped Suricata workloads; workload-dependent |
| Source rate | 6,000–13,000 alerts/hour | Long-running homelab deployment |
| v0.3 end-to-end accuracy | 99.624% | Approved 266-alert operator evaluation |
| v0.3 end-to-end true-positive recall | 100% | Same approved evaluation |
| Local-model latency | 7–10 seconds per residual alert | Foundation-Sec-8B Q5_K_M on RTX 4060 |
The evaluation is versioned and reproducible. Read the gold-set methodology, the v0.3 release evidence, and the model experiment notes. TriageWall does not present these numbers as guarantees for every network or model.
- Docker Engine 20.10+ and Docker Compose v2
- Ollama on the same host or another reachable private host
- 8 GB+ GPU VRAM recommended for the default residual-alert model
git clone https://github.com/aaronphifer/triagewall.git
cd triagewall
cp .env.example .envOn the Ollama host, pull the default model before starting TriageWall:
ollama pull hf.co/gabriellarson/Foundation-Sec-8B-Instruct-GGUF:Q5_K_MSet DEMO_MODE=true in .env, then start the stack:
docker compose up -dOpen http://localhost:8084. Demo mode uses bundled fixtures, masks addresses, and disables writes so you can inspect the workflow before connecting a sensor.
For a real deployment, set DEMO_MODE=false and configure the Suricata data
path, persistent data directory, Ollama host/model, and internal networks in
.env. The operations guide covers the complete setup,
database startup, storage, retention, model selection, and tuning workflow.
The opt-in docker-compose.wazuh.yml profile reads a same-host Wazuh manager's
alerts.json from a local read-only volume. It uses no Wazuh API credential and
receives no Docker socket. See the
Wazuh integration guide for startup, archive
recovery, verification, and rollback.
Configuration writes are disabled by default and require an attributable
config:write API key. Generate one from a private terminal:
python scripts/generate_api_key.pyStore the generated hash-only record in .env, retain the one-time plaintext
key, set TRIAGEWALL_CONFIG_WRITES_ENABLED=true, and restart the dashboard.
The API authentication guide documents scopes
and deployment boundaries.
flowchart LR
S["Suricata eve.json"] --> SA["Suricata adapter"]
W["Wazuh alerts.json"] --> WA["Wazuh adapter"]
SA --> P{"Scoped policy match?"}
P -->|yes| DB["SQLite decision history"]
P -->|no| L["Local Ollama model"]
WA --> L
L --> DB
DB --> UI["Analyst workbench"]
UI --> O["Operator review"]
UI --> C["Versioned configuration"]
C -. "explicit activation" .-> P
TriageWall Core is the supported operational product. A future TriageWall Lab will provide isolated replay and evaluation without weakening Core's production boundary. Read the Core/Lab product boundary.
- Alert evidence and model inference stay on operator-controlled hardware.
- Sensor records are treated as untrusted input and projected through source-specific isolation before local-model evaluation.
- The application is read-only with respect to Suricata and Wazuh.
- Configuration mutation is default-off, API-key-only, attributable, audited, previewed, and explicitly activated.
- Database migration has one startup owner; consumers fail closed on incomplete or invalid schema/configuration state.
- Release gates cover deterministic behavior, configuration lifecycle, authorization, browser concurrency, checkpoints, and source-specific regressions.
Read SECURITY.md before reporting a vulnerability and the threat model for defended boundaries, assumptions, and known limitations.
| Integration | Status | Notes |
|---|---|---|
Suricata eve.json |
Core | Durable checkpoints and fail-closed rotation recovery |
Wazuh alerts.json |
Optional | Local read-only volume and source-aware projection |
| Ollama | Core | Local inference; no cloud-model dependency |
| SQLite | Core | WAL-backed decision, feedback, configuration, and audit history |
| Docker Compose v2 | Supported deployment | Core-only and optional Core + Wazuh profiles |
- Operations and deployment
- Wazuh integration
- HTTP API and authentication
- Operator configuration lifecycle
- Threat model
- Gold-set release gate
- Release evidence
- Model and security experiments
- Product roadmap
- Changelog
- It does not block traffic or invoke active response.
- It does not replace Suricata, Wazuh, a firewall, or an endpoint agent.
- It does not make every alert correct; uncertain and false-negative outcomes remain possible and the operator stays in the loop.
- It does not provide cloud identity, multi-tenant authorization, or an internet-facing SaaS control plane.
Bug reports and feature requests use the repository's structured issue forms. Use GitHub Discussions for questions and implementation ideas. Read SUPPORT.md for the support boundary and CONTRIBUTING.md before opening a pull request.
If TriageWall is useful to you, GitHub Sponsors helps fund release validation, testing hardware, local-model evaluation, and documentation. Sponsorship does not change the open-source license or replace commercial licensing.
TriageWall is licensed under AGPL-3.0. Commercial licenses are
available for organizations that need to ship TriageWall without AGPL section
13 compliance; contact licensing@triagewall.io.
Built with Suricata, Wazuh, Ollama, FastAPI, and the self-hosted security community.

