Console & fleet

SIEM export (Enterprise)

An Enterprise daemon can mirror every audit event into a local directory in three formats, newline-delimited JSON, CEF and RFC 5424 syslog, so the SIEM forwarder you already run can ingest them. This page is the operator's reference: the formats with an example line each, the fields, the configuration file and the per-mode behavior.

~6 min read · Console & fleet

What it is

A local, file-based mirror of the daemon's audit trail:

  • Every audit action is mirrored: allow, revert, quarantine, quarantine_reversible, detected_kept, meta_attack and fail_closed.
  • Three formats, each an independently enabled rotating file: JSON lines, CEF (ArcSight Common Event Format) and syslog (RFC 5424).
  • Local and air-gap safe: the daemon writes files to disk; the only optional network path is a syslog target you configure on your own network. Nothing is sent to the PoisonZero cloud.
  • Best-effort and fail-open: every init and write error is swallowed; the export can never delay or block enforcement.
The forensic source of truth remains the vault's owner-only audit.log (see incidents and audit). The SIEM files are a mirror for ingestion, not a replacement.

Enabling it

The export is configured by one local file, siem.json, in the daemon's config directory. It is deliberately not cloud-managed: no remote config can switch it on or redirect it. Edit the file, then restart the daemon:

PlatformPath
Linux/etc/poisonzero/siem.json
macOS / Windows<config dir>/siem.json (override the directory with POISONZERO_CONFIG_DIR)
jsonsiem.json
{
  "enabled": true,
  "dir": "/var/log/poisonzero-siem",
  "formats": ["json", "cef", "syslog"],
  "syslog_target": "siem.example.com:514",
  "syslog_network": "udp",
  "group": "splunk"
}
FieldMeaning
enabledMaster switch. false or a missing file means the export is off.
dirOutput directory; created with mode 0755 if missing.
formatsAny subset of json, cef, syslog. Each enabled format writes one rotating file.
syslog_targetOptional host:port of a live syslog receiver. Omit it for file-only output.
syslog_networkudp (default) or tcp.
groupOptional read group for the export files (Linux/macOS): the directory becomes 0750, the files 0640, both owned by that group. Ignored on Windows. See permissions below.
A missing file, enabled: false, an empty dir or formats list, or unparseable JSON all resolve the same way: export off, daemon running. A failed connection to syslog_target is also swallowed; the file mirror keeps writing.

Output files, rotation and permissions

FileContent
audit.jsonOne JSON object per line
audit.cefOne CEF line per event
audit.syslogOne RFC 5424 line per event; the same line also goes to syslog_target if set
  • Rotation: each file rotates to *.1 at 10 MiB, so the mirror is size-bounded on disk.
  • Default permissions: the directory is created 0755, the files are written 0600. The lines carry file paths and reasons, so by default only the daemon's own user may read them. On start the daemon also resets inherited group permissions back to these defaults.
  • Forwarder access via group (Linux/macOS): a forwarder running as its own unprivileged user (splunk, nxlog, td-agent) gets read access through the optional group field: the directory becomes 0750, the files 0640, both owned by that group - including every fresh file created by rotation, which a plain file ACL would not survive. Add the forwarder user to that group.
  • Fail-safe: if the group does not exist or setting group or mode fails, the export does not start (logged once). Files are never left with wrong permissions.
  • Revoking: remove the field and the next daemon start resets directory and files back to 0755/0600; already rotated *.1 files are corrected at their next rotation.
  • Windows: the field is ignored - POSIX modes do not apply there. Grant the forwarder account read access via the inherited directory ACL.
Use a dedicated forwarder group. Never a broad group such as staff (on macOS: every local user), users, wheel or everyone: that hands the detection lines to the monitored agent process and every local user - exactly what the 0600 default prevents. Create a dedicated group (for example pz-siem, or the forwarder's own group such as splunk) and add only the forwarder user. The daemon logs a warning at startup if a broad system group is configured.

The JSON line

Each line is one audit entry; empty optional fields are omitted:

KeyTypeMeaning
tsstringRFC 3339 UTC. Stamped at render time if the entry had none.
actionstringOne of the audit actions listed above. detected_kept means detected but deliberately left untouched: a detection, never counted as a block.
pathstringAbsolute path of the affected file.
reasonstringHuman-readable reason or classifier message.
dangernumber0 to 1, present only for AI decisions.
threat_levelstringlow, medium or high: the derived severity tier, and the first input to CEF and syslog severity.
app_idstringDaemon identity; stamped from the daemon's own identity when the entry carries none.
agentstringAgent name, when known.
categorystringAttack category, when the model populated it.
groundedbooleanWhether the evidence is verbatim in the evaluated change; only present when there is evidence.
evidence_sha256, evidence_lengthstring, numberSHA-256 and length of the evidence quote. The quote itself is never written; see below.
jsonaudit.json line
{"ts":"2026-06-10T12:00:00Z","action":"revert","path":"/home/dev/.claude/CLAUDE.md","reason":"prompt injection: exfiltration instruction","danger":0.93,"app_id":"app-7c1","agent":"claude-code","category":"exfil","threat_level":"high","evidence_sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","evidence_length":72}
The verbatim evidence quote never leaves the vault through this export. Every format carries only its SHA-256 and length, the same redaction rule as the default level of the OpenTelemetry export.

The CEF line

Header: CEF:0|PoisonZero|PoisonZero|<daemon-version>|<action>|<action>|<severity>|<extensions>. Reserved characters are CEF-escaped in both header and extension values. The extensions map:

CEF keySourceNotes
rttsEvent time (RFC 3339).
actactionDecision taken.
fnamepathAffected file.
msgreasonReason or classifier message.
appapp_idDaemon identity.
suseragentAgent name.
cs1categoryWith cs1Label=Category.
cs2threat_levelWith cs2Label=ThreatLevel.
cn1dangerWith cn1Label=Danger.

Severity (CEF 0 to 10) is driven by the threat level first: high is 9, medium is 6, low is 2. Only an entry without a threat level falls back to its action: quarantine 10; revert, meta_attack, fail_closed 9; quarantine_reversible, detected_kept 6; allow 2; an unknown action ranks by danger. In live data the level decides: a proven quarantine is high (9), a detected_kept is medium (6), so the two are already separated.

textaudit.cef line
CEF:0|PoisonZero|PoisonZero|0.7.8|revert|revert|9|rt=2026-06-10T12:00:00Z act=revert fname=/home/dev/.claude/CLAUDE.md msg=prompt injection app=app-7c1 suser=claude-code cs2=high cs2Label=ThreatLevel cn1=0.93 cn1Label=Danger

The syslog line

RFC 5424, facility local0 (16), so PRI = 16 × 8 + severity. The message body is the CEF line above: CEF over syslog, the common SIEM convention. Severity mirrors the CEF logic, threat level first:

InputSyslog severity
Threat level highwarning (4)
Threat level mediumnotice (5)
Threat level lowinformational (6)
No level: quarantine, revert, meta_attack, fail_closedwarning (4)
No level: quarantine_reversible, detected_keptnotice (5)
No level: allow and anything elseinformational (6)
textaudit.syslog line
<132>1 2026-06-10T12:00:00Z build-host poisonzero - audit - CEF:0|PoisonZero|PoisonZero|0.7.8|revert|revert|9|rt=2026-06-10T12:00:00Z act=revert ...
detected_kept stays at notice on purpose: an operator filtering at notice and above still sees the detection. It is still never counted as a block.

Modes and air gap

The export behaves identically in Cloud mode and Private mode: it is a purely local sink, so a Private device loses nothing (see cloud or private). The feature makes no outbound connections of its own; the only network path is the syslog_target you explicitly configure, on your own network. In a fully air-gapped deployment, leave syslog_target unset and have your on-premises collector tail the files.

SIEM export or OpenTelemetry export?

Both are Enterprise features and both stay inside your network; they answer different questions:

SIEM exportOpenTelemetry export
TransportLocal files (plus optional syslog forwarding)OTLP/HTTP push to a collector
ScopeEvery audit action, allow includedDetection events; allow is never exported
FormatsJSON lines, CEF, RFC 5424 syslogOTLP with fixed poisonzero.* attributes
Detail levelsNone: evidence is always hash plus lengthhashes, redacted, full (local decision)
ConfigurationOne local file, never cloud-managedLocal profile or central Admin API for fleets

What the audit trail itself records: incidents and audit. How long local data is kept: storage, retention and cleanup. The mode choice behind it all: cloud or private.

Was this helpful?

Your audit trail, in the SIEM you already run.

JSON, CEF and syslog, written locally and ingested by your own forwarder. No cloud in the path. An Enterprise feature.

Sign me up