diff --git a/src/fgai/correlation.py b/src/fgai/correlation.py
index 33cfc48..28f9dff 100644
--- a/src/fgai/correlation.py
+++ b/src/fgai/correlation.py
@@ -17,5 +17,13 @@ def correlate_source_ips(events: list[LogEvent], *, limit: int = 20) -> list[dic
if len(streams) < 2:
continue
threat_events = sum(event.action in THREAT_ACTIONS or is_utm_event(event) for event in source_events)
- correlations.append({"source_ip": source_ip, "streams": streams, "events": len(source_events), "security_events": threat_events})
+ samples = [
+ {
+ "stream": event.fields.get("fgai_stream", "local_syslog"), "timestamp": event.fields.get("eventtime", event.fields.get("timestamp", "")),
+ "type": event.fields.get("type", ""), "subtype": event.subtype, "action": event.action,
+ "severity": event.severity, "destination": event.dst_ip or "", "service": event.fields.get("service", ""),
+ }
+ for event in source_events[:20]
+ ]
+ correlations.append({"source_ip": source_ip, "streams": streams, "events": len(source_events), "security_events": threat_events, "samples": samples})
return sorted(correlations, key=lambda item: (int(item["security_events"]), int(item["events"])), reverse=True)[:limit]
diff --git a/src/fgai/dashboard.py b/src/fgai/dashboard.py
index cb53e9d..2febba4 100644
--- a/src/fgai/dashboard.py
+++ b/src/fgai/dashboard.py
@@ -62,7 +62,7 @@ HTML = """
AI Assessment
LLM assessment disabled.
-
+ Related Activity Across Sources
@@ -139,6 +139,12 @@ async function refresh() {
{label:'Reasons', render:r => esc((r.reasons || []).join('; '))}
]);
const reputationRows = Object.entries(data.reputation || {}).map(([ip, intel]) => ({ip, ...intel}));
+ const relatedRows = (data.cross_source_correlations || []).flatMap(correlation => (correlation.samples || []).map(sample => ({source_ip: correlation.source_ip, ...sample})));
+ document.getElementById('relatedActivity').innerHTML = table(relatedRows, [
+ {label:'Source IP', key:'source_ip'}, {label:'Stream', key:'stream'}, {label:'Time', key:'timestamp'},
+ {label:'Type', key:'type'}, {label:'Action', key:'action'}, {label:'Severity', key:'severity'},
+ {label:'Destination', key:'destination'}, {label:'Service', key:'service'}
+ ]);
document.getElementById('reputation').innerHTML = table(reputationRows, [
{label:'IP', key:'ip'},
{label:'Provider', key:'provider'},
diff --git a/tests/test_correlation.py b/tests/test_correlation.py
index 9068ed6..72b7f4d 100644
--- a/tests/test_correlation.py
+++ b/tests/test_correlation.py
@@ -13,3 +13,4 @@ class CorrelationTests(unittest.TestCase):
result = correlate_source_ips(events)
self.assertEqual(result[0]["source_ip"], "10.0.0.5")
self.assertEqual(result[0]["streams"], ["DNS", "Fortigate"])
+ self.assertEqual(len(result[0]["samples"]), 2)