/ projects / carl
CARL
Offline SOC knowledge base that captures what lives in analysts' heads
Built into it
- Three-phase routing engine
- KQL-ready alert playbooks
- Investigation primitives library

Problem
SOC tribal knowledge lives in people, not documentation. When an analyst hits a phishing alert at 2 AM, the response steps exist — but only in the heads of senior analysts who are off-shift. Onboarding runbooks go stale fast and miss the edge cases experienced analysts handle by instinct.
Approach
CARL (Contextual Alert Response Library) is a deterministic, offline knowledge base with no LLM dependency. It runs entirely in the browser on the analyst workstation, never makes an external call, and produces the same output for the same query every time. Alert-type lookups return structured playbooks with step-by-step investigation paths. The store holds 500+ entries — alert playbooks, investigation primitives, MITRE ATT&CK techniques, LOLBin databases, file-path masquerading patterns — resolved through eight dispatch engines and a keyword scoring layer, not a language model.
Here’s what the playbook surface looks like for a phishing-cred-harvest alert against a synthetic contoso.com tenant — click or arrow-key through the four steps:
Six-hour window surrounding the click. Successful auths first, risk attribute carried.
SigninLogs
| where TimeGenerated between (datetime('2026-04-21T14:00:00Z') ..
datetime('2026-04-21T20:00:00Z'))
| where UserPrincipalName == '[email protected]'
| project TimeGenerated, IPAddress, ResultType, RiskLevelDuringSignIn
| sort by TimeGenerated desc Any auto-forward / delete-on-receive rule created after the suspicious event.
AuditLogs
| where TimeGenerated > ago(6h)
| where OperationName == 'New-InboxRule'
| where TargetResources[0].userPrincipalName == '[email protected]'
| project TimeGenerated, RuleName=Result,
Conditions=AdditionalDetails New or updated security-info entries on the affected account.
AuditLogs
| where TimeGenerated > ago(24h)
| where OperationName in (
'Add a security info to user',
'Update a security info from user')
| where TargetResources[0].userPrincipalName == '[email protected]'
| project TimeGenerated, OperationName, IPAddress Sender pattern from the staging domain across the contoso.com tenant.
EmailEvents
| where Timestamp > ago(72h)
| where SenderFromAddress endswith '@phish-staging.example.com'
| where RecipientEmailAddress endswith '@contoso.com'
| summarize Count=count(),
Recipients=dcount(RecipientEmailAddress) Running offline in the browser means it works behind strict network controls and nothing leaves the machine. Determinism means the same query always returns the same answer — which is the property that holds up in an audit conversation.
Outcome
Analysts work through unfamiliar alert types without waiting for a senior to come online. New-hire ramp shortens because the implicit response patterns are now explicit, searchable, and versioned in git.
What’s next
An asset-inventory CSV import pipeline is in progress. Once it lands, lookups can return environment-specific network ranges and escalation contacts instead of generic placeholders.
/ related · 03
Other projects
- 01
BASTION
KQL investigation toolkit that ends the rebuild-from-scratch loopHTML JavaScript Python FastAPIActive - 02
KQL Sentinel Lab
Synthetic Sentinel environment for analysts to practice on real attack dataHTML JavaScript Python FastAPIActive - 03
ThreatWatch
Curated threat intel delivery from RSS feeds to Slack, automated dailyHTML JavaScript Python FastAPIActive