Syslog Alerting¶
AC-Hunter can forward newly detected threats to an external syslog server as they are scored. This is the standard way to wire AC-Hunter into a SIEM, log aggregator, or SOAR pipeline so analysts get notified without having to watch the dashboard.
This page describes how alerts fire, the wire format, how to configure delivery, and how to test the connection.
When alerts fire¶
Alerts are evaluated per sensor, once per import. AC-Hunter ingests Zeek logs in batches (typically hourly); after each batch finishes scoring, the alerting pipeline runs against that sensor's results.
For each import, AC-Hunter looks at every scored threat (a src → dst/fqdn connection that crossed your configured threshold) and decides whether to send an alert:
- First import for a sensor: every threat over the configured minimum threat level is alerted on. Each alert is marked
"is_new_threat": true. - Subsequent imports: AC-Hunter compares the new import against the previous one. Alerts fire for:
- Brand-new threats that weren't present in the previous import. These are marked
"is_new_threat": true. - Threats whose level increased since the previous import (e.g. Medium → High). These are marked
"is_new_threat": false.
- Brand-new threats that weren't present in the previous import. These are marked
Threats that stayed at the same level or decreased do not trigger alerts. The same threat will not re-alert on every import — only when something about it changes.
State is tracked per sensor in AC-Hunter's metadata, so each sensor's alerting timeline is independent.
Threat levels¶
Each alert carries a categorical threat_level:
| Level | Meaning |
|---|---|
Critical |
Highest-severity threats |
High |
High-severity threats |
Medium |
Moderate-severity threats |
Low |
Low-severity threats |
Categories are derived from each threat's numeric score. See Analysis Overview for details on how scores are computed.
The Minimum threat level setting controls the floor: only threats at or above that level produce alerts. For example, setting it to High will send Critical and High alerts but suppress Medium and Low.
Configuration¶
Syslog is configured in the web UI under Settings → Alerts.
| Field | Description |
|---|---|
| Enabled | Master on/off switch for syslog alerting |
| Hostname | Hostname or IP of your syslog receiver |
| Port | Port your receiver listens on. Defaults: 514 for UDP/TCP, 6514 for TLS |
| Protocol | udp, tcp, or tls |
| Tag | Syslog tag / program identifier (default AC-HUNTER) |
| Minimum threat level | Lowest level that triggers an alert: Low, Medium, High, or Critical |
| AC-Hunter public address | Hostname or URL used to build the url field in each alert (typically the AC-Hunter web URL your analysts use) |
Public address vs. server hostname
The AC-Hunter public address is what appears in the url field of each alert and is what your analysts will click to drill in. Set it to the externally reachable URL — not localhost — so the links work from wherever alerts are read.
After saving, AC-Hunter applies the new configuration immediately. There is no need to restart services.
Alert format¶
Each alert is a single line of JSON sent at syslog priority LOG_ALERT, with the syslog tag set to your configured Tag value.
{
"sensor": "zeek_hq_01",
"url": "https://ach.example.com/sensor/details/<connection-hash>",
"src": "10.0.0.5",
"dst": "8.8.8.8",
"fqdn": "evil.example.com",
"threat_level": "Critical",
"is_new_threat": true
}
Field reference¶
| Field | Type | Description |
|---|---|---|
sensor |
string | Name of the Zeek sensor (or Espy server) that produced the logs containing this threat |
url |
string | Direct link to the scored connection in the AC-Hunter UI. Combines the configured public address with the connection's hash |
src |
string | Source IP of the connection |
dst |
string | Destination IP of the connection. May be empty for FQDN-only threats (e.g. C2-over-DNS) |
fqdn |
string | Fully-qualified domain name associated with the connection, if known. Empty for IP-only threats |
threat_level |
string | One of Critical, High, Medium, Low |
is_new_threat |
boolean | true if this threat did not exist in the previous import; false if it existed but the threat level increased |
One alert per scored threat¶
Unlike a per-host summary, each alert represents a single scored connection — one src to one dst/fqdn pair. A host involved in multiple suspicious connections will produce one alert per connection, each with its own url. This makes alerts easier to ingest as discrete events in downstream systems and lets you correlate per-connection rather than per-host.
Rate limiting (UDP)¶
When the syslog protocol is udp, AC-Hunter rate-limits to roughly 10 alerts per second to avoid the receiver dropping packets under load. TCP and TLS deliveries are not rate-limited.
Testing the connection¶
After configuring syslog, you can send a test alert from the AC-Hunter server without waiting for a real threat:
This connects to the configured receiver using your current settings and writes the literal string Ping from AC-Hunter! at LOG_ALERT priority with your configured tag. The command prints diagnostic output as it goes:
- On success: confirms the dial succeeded and the test alert was sent.
- On failure to dial: AC-Hunter will additionally attempt a generic TCP/UDP connection to the same host:port and report whether the network path itself is reachable. This separates "syslog daemon refused the connection" from "host unreachable" / "firewall dropping the packets."
Use hunt syslog-alert-ping whenever you change network settings, rotate certificates (for TLS), or change syslog receivers — it's faster than waiting for the next import cycle.
Receiver-side considerations¶
A few things to keep in mind on the receiving end:
- Filtering by tag. AC-Hunter sets the syslog tag to your configured Tag value (default
AC-HUNTER). Most receivers can route messages with that tag into a dedicated file or pipeline. - JSON parsing. Each message body is a complete single-line JSON object. Receivers that support JSON parsers (rsyslog
mmjsonparse, syslog-ngjson-parser, Vector, Logstash, etc.) can ingest alerts directly into structured fields. - TLS. When protocol is
tls, AC-Hunter currently connects withInsecureSkipVerifyset, so self-signed receiver certs are accepted. Use TLS for transport encryption; do not rely on it for receiver-identity verification in the current implementation. - UDP packet size. Alert payloads are usually a few hundred bytes. UDP is fine for most deployments, but if you expect very large bursts (e.g. on a sensor's first import), TCP or TLS will be more reliable.
Troubleshooting¶
| Symptom | Where to look |
|---|---|
| No alerts arrive after the next import | Confirm Settings → Alerts → Enabled is on, and that recent threats are at or above the configured minimum threat level. Run hunt syslog-alert-ping to isolate config vs. trigger issues |
hunt syslog-alert-ping reports "Unable to connect to syslog server" |
Check Hostname, Port, Protocol, and any firewall between AC-Hunter and the receiver. AC-Hunter will follow up with a generic-connection test that distinguishes refused vs. unreachable |
| Test alert succeeds but real alerts don't appear | Verify the same sensor is producing imports (see Server Administration). Alerts only fire when a new import is processed |
| Receiver sees malformed text instead of JSON | Some receivers split syslog message bodies on whitespace or special characters. Make sure your parser is configured to take the entire message body |
url field points to localhost or an unreachable address |
Update AC-Hunter public address under Settings → Alerts to the externally-reachable URL |
For deeper investigation, check the AC-Hunter middleware logs (hunt logs api) around the import time. The alerting pipeline emits structured log entries including alerts_sent, the destination, and any per-alert delivery errors.