+

Local research workspace ยท response controls below create dry runs ยท topology and risk scores are simulated until a lab is connected.

@@ -2082,6 +2083,15 @@
+
+
+
Defense Plans & Audit
+ +
+
Loading saved plans...
+ +
+
@@ -2091,7 +2101,7 @@
-
Network Topology
+
Simulation Topology
DMZ
@@ -2156,7 +2166,7 @@
@@ -2185,7 +2195,7 @@
-
Security Risk Scores
+
Simulation Risk Scores
--
@@ -2284,7 +2294,7 @@ // โ”€โ”€ CONSTANTS โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ const ANALYST_ID = 'analyst-1'; const KILL_CHAIN_STAGES = ['RECON','ACCESS','EXEC','PERSIST','PRIV ESC','LATERAL','COLLECT','C2','EXFIL','IMPACT']; -const KILL_CHAIN_KEYS = ['recon','initial_access','execution','persistence','privilege_escalation','lateral_movement','collection','command_and_control','exfiltration','impact']; +const KILL_CHAIN_KEYS = ['reconnaissance','initial_access','execution','persistence','privilege_escalation','lateral_movement','collection','command_and_control','exfiltration','impact']; let refreshTimer = null; // โ”€โ”€ UTILITY โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ @@ -2422,12 +2432,12 @@ if (riskRes.status === 'fulfilled' && riskRes.value.ok) { const d = riskRes.value.data; const grade = d.overall_security_posture_rating || d.grade || '--'; - const score = d.overall_score || d.score || 0; + const score = d.average_risk_score ?? null; const gradeEl = document.getElementById('mb-grade'); gradeEl.textContent = grade; gradeEl.className = `grade-chip ${gradeClass(grade)}`; document.getElementById('mb-score-bar').style.width = `${Math.min(score, 100)}%`; - document.getElementById('mb-score-num').textContent = `${Math.round(score)}/100`; + document.getElementById('mb-score-num').textContent = score == null ? 'N/A' : `${Math.round(score)}/100`; } // Workers @@ -2547,14 +2557,14 @@ html += `
- ${(a.severity||'INFO').toUpperCase()} - ${timeAgo(a.timestamp)} - ${a.category || a.alert_type || ''} + ${escHtml((a.severity||'INFO').toUpperCase())} + ${timeAgo(a.timestamp || a.added_at)} + ${escHtml(a.category || a.alert_type || '')}
-
${a.alert_id || a.id || 'alert-'+idx}
+
${escHtml(a.alert_id || a.id || 'alert-'+idx)}
-
Rule: ${a.rule_description || 'N/A'}
-
${a.source_ip || '?'} → ${a.destination_ip || '?'}
+
Rule: ${escHtml(a.rule_description || 'N/A')}
+
${escHtml(a.source_ip || '?')} → ${escHtml(a.dest_ip || '?')}
${a.full_log ? `
${escHtml(a.full_log)}
` : ''}
`; @@ -2573,8 +2583,8 @@ const tactics = incident.mitre_tactics || []; if (techniques.length || tactics.length) { html += `
MITRE ATT&CK
`; - tactics.forEach(t => { html += `${t}`; }); - techniques.forEach(t => { html += `${t}`; }); + tactics.forEach(t => { html += `${escHtml(t)}`; }); + techniques.forEach(t => { html += `${escHtml(t)}`; }); html += `
`; } @@ -2582,10 +2592,10 @@ html += `
Threat Intelligence (RAG)
Querying...
`; // Historical context - const srcIPs = Array.from(new Set((incident.alerts||[]).map(a=>a.source_ip).filter(Boolean))); + const srcIPs = incident.source_ips || []; html += `
Historical Context
`; if (srcIPs.length) { - srcIPs.slice(0,2).forEach(ip => { html += `
Loading history for ${ip}...
`; }); + srcIPs.slice(0,2).forEach(ip => { html += `
Loading history for ${escHtml(ip)}...
`; }); } else { html += `
No source IPs identified.
`; } @@ -2613,7 +2623,7 @@ const res = await apiFetch('/api/rag/retrieve', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ query, top_k: 3, n_results: 3 }), + body: JSON.stringify({ query, top_k: 3, min_similarity: 0.2 }), }); if (!res.ok || !res.data) { @@ -2631,7 +2641,7 @@ results.slice(0, 3).forEach(r => { const tid = r.technique_id || r.id || r.metadata?.technique_id || ''; const desc = r.description || r.text || r.content || r.document || ''; - html += `
${tid}
${escHtml(desc).slice(0, 200)}${desc.length > 200 ? '...' : ''}
`; + html += `
${escHtml(tid)}
${escHtml(desc).slice(0, 200)}${desc.length > 200 ? '...' : ''}
`; }); el.innerHTML = html || '
No results.
'; } @@ -2643,7 +2653,7 @@ for (const ip of ips) { const res = await apiFetch(`/api/alerts?source_ip=${encodeURIComponent(ip)}&limit=5`); const alerts = res.ok ? (Array.isArray(res.data) ? res.data : (res.data.alerts || [])) : []; - html += `
${alerts.length} previous alerts from ${ip} (last 5 fetched)
`; + html += `
${alerts.length} previous alerts from ${escHtml(ip)} (last 5 fetched)
`; } container.innerHTML = html || '
No history found.
'; } @@ -2651,14 +2661,12 @@ function buildActionsPanel(alertId, incidentId) { return `
- - - +
- @@ -2669,7 +2677,7 @@
- @@ -2683,7 +2691,7 @@
- @@ -2691,15 +2699,15 @@
- +
- +
Detection Rule Generation
- -

-