ADR 0007: Timestamp normalisation across collectors¶
- Status: accepted (v0.2)
- Date: 2026-09-26
Context¶
OTRF captures are exported through NXLog and Logstash, so each row carries several clocks:
- Sysmon
UtcTime: authoritative UTC, set by the Sysmon driver. EventTime/TimeCreated: when Windows wrote the record, in the collector's local time, sometimes with a misleadingZsuffix, and whole seconds only.@timestamp: when Logstash ingested the row. On the APT29 capture it lags real time by 1–45 s.
The first v0.2 benchmark run preferred @timestamp for non-Sysmon rows. Security
4688 records then landed up to 45 s after their Sysmon twins, fusion failed to
merge them, and the orphaned 4688 became the "nearest cause" of later events.
APT29 edge F1 read 0.635 because of a clock choice, not a reasoning error.
Decision¶
- Sysmon rows use
UtcTime. - Other rows use the first of
TimeCreated,EventTime,@timestamp(ingest time is the last resort), shifted by a per-field offset estimated as the median offield - UtcTimeover Sysmon rows and snapped to 15 minutes (time-zone granularity). - auth.log carries no year or zone, so both are explicit parameters, never
guesses.
.evtxSystemTimeis already UTC. - Clock manipulation is a separate question, handled by anti-forensics (4616 jumps, record-number order vs time order).
Consequences¶
- After the fix, APT29 edge F1 is 1.000 (see
results/edges.json). - The offsets used are reported in every analysis (
load_stats.clock_offsets_s). - Captures without any Sysmon rows cannot be offset-corrected automatically. Their times are taken as UTC, which the report states under "What remains uncertain".