3.2 KiB
Defect: Windows scan timestamps lose their UTC offset
Status
Open and reproducible in the accepted Windows worker package validated on 2026-09-25. The live validation did not modify product code so that the tested package remained identical to the accepted artifact.
Symptom
Windows scan.result_error diagnostics can be stored with occurred_at about
the machine's local UTC offset in the future. In the validation environment the
offset was approximately three hours. The same naive timestamps also populate
Windows target_scans.started_at and target_scans.ended_at.
This can misorder diagnostics, distort time-window filters, and make the admin panel show a scan event later than the server receipt that contains it.
Live evidence
The accepted Windows package ran with a fresh state directory and one slot. In
the expanded live cohort, all 45 Windows scan.result_error diagnostics had an
occurred_at to server received_at delta between approximately 10,816 and
10,819 seconds. All 135 normal Windows scan-result rows used naive local start
and end timestamps with the same approximately three-hour displacement when
treated as UTC. The four Windows timeout-path rows and all 102 Linux rows had
normal small timing deltas.
The retained raw scanner material contained an explicit +03:00 timestamp.
The persisted diagnostic retained the same wall-clock digits but labeled them
as UTC with Z. Monotonic scan durations and worker progress transport
timestamps remained correct.
Sensitive raw targets, scanner output, and credentials are retained only in the restricted live evidence file and are intentionally not reproduced here.
Root cause
app/scanner.py creates scan timestamps with naive local datetimes:
scan_target_result()usesdatetime.now().isoformat()forscan_started_atandtimestampnear lines 16339 and 16416.- fallback result construction in
scan_single_target()does the same near lines 16844, 16863, and 16877.
Diagnostic construction parses those values and, when no timezone is present,
uses occurred.replace(tzinfo=timezone.utc) near line 16581. That operation
relabels local wall-clock time as UTC instead of converting it. The error is
visible on non-UTC hosts and is hidden on UTC Linux hosts.
Expected behavior
All persisted protocol timestamps must identify a real UTC instant. Scanner result timestamps should be emitted as timezone-aware UTC values, and legacy naive values must not be silently reinterpreted as known UTC instants.
Suggested correction and regression coverage
Emit datetime.now(timezone.utc).isoformat() at every result-construction site
and preserve the offset through serialization. Add a non-UTC-host regression
test that verifies:
- scanner start/end timestamps identify the actual UTC instant;
- diagnostic
occurred_atprecedes or closely tracks serverreceived_at; - Windows and Linux admin time-window filters return the same logical events;
- monotonic duration fields remain unchanged.
Validation artifact
The expanded unrestricted evidence is retained at
build/live-trace-20260925/raw-evidence-expanded.json. It contains sensitive
raw internals and must not be published as a general operator report.