๐ Documentation v1.0.0
Complete reference for the FusionSOC Agentic Cyber Defense Platform
1. Overview
FusionSOC is an AI-powered Security Operations Center platform built by Fusion Cybersecurity. It integrates with LimaCharlie EDR to continuously ingest, enrich, triage, and respond to security detections โ fully autonomously or with human-in-the-loop approval.
FusionSOC is the defensive counterpart to FusionTester (our automated pentesting pipeline). Where FusionTester attacks, FusionSOC defends.
Key Capabilities
- Continuous Detection Polling โ Background polling of the LimaCharlie Insight API every 30 seconds with cursor-based pagination, deduplication, and 24-hour backfill on first startup
- Contextual Enrichment โ Every detection is enriched with sensor metadata (hostname, IP, OS, tags), process tree (parent/child chains via atom traversal), recent sensor events (30-minute window), D&R rule metadata, and MITRE ATT&CK technique mappings
- Multi-Model Voting Triage โ 3 local LLM models (e.g. qwen3.5:4b, qwen3:4b, deepseek-r1:8b) analyze each detection in parallel. Unanimous verdicts trigger auto-action: all-FP โ auto-close, all-TP โ escalate to Incident Response. Split votes โ manual review. Gemini CLI available as primary with Ollama fallback (qwen3.5:27b) for single-model mode
- Custom Case Management โ SQLite-backed case system with automatic case creation, intelligent detection grouping (same sensor + category + 30-minute window), full timeline audit trails, analyst notes, and SOC metrics (MTTR, open case counts)
- Smart Action Execution โ Recommended actions like "check for lateral movement" are mapped to real LimaCharlie API investigation queries (NEW_REMOTE_THREAD, NETWORK_CONNECTIONS, etc.). Results stored as detailed case notes. Also supports sensor tagging and process kill with safety controls
- Raw JSON Viewer โ Collapsible raw detection JSON and AI triage JSON viewers in every case detail page for analyst transparency
- Hide Closed Cases โ Toggle button on the cases page to show/hide closed and resolved cases
- Real-Time Dashboard โ Flask + WebSocket dashboard with dark cyberpunk theme, live detection feed, case management UI, sensor inventory, and response action queue
FusionSOC follows a "safe by default" principle. All destructive actions (network
isolation, process kill) are disabled out of the box. The system will analyze and triage detections
automatically, but containment actions require explicit opt-in via config.yaml and/or
manual approval through the dashboard.
2. Architecture
System Diagram
Data Flow
At every stage, sensors are tagged with pipeline step markers (fusion-soc-pulled,
fusion-soc-triage, fusion-soc-case, fusion-soc-alert) for full
observability.
Module Reference
| Module | File | Purpose |
|---|---|---|
config |
fusionsoc/config.py | YAML + .env config loader with ${VAR} interpolation |
utils |
fusionsoc/utils.py | Logging setup, timestamp helpers, severity mapping |
lc_client |
fusionsoc/lc_client.py | LimaCharlie REST API wrapper โ JWT auth, 30+ endpoint methods |
models |
fusionsoc/models.py | SQLAlchemy ORM โ 6 database tables |
poller |
fusionsoc/poller.py | Background detection polling with cursor pagination & dedup |
enricher |
fusionsoc/enricher.py | Detection context enrichment (sensor, process tree, MITRE) |
triage |
fusionsoc/triage.py | Multi-model voting triage engine (3 Ollama models in parallel) |
case_manager |
fusionsoc/case_manager.py | Case creation, grouping, status workflow, notes, metrics |
responder |
fusionsoc/responder.py | Smart investigation + response actions with safety controls |
dashboard |
dashboard/app.py | Flask + SocketIO web application (routes, API, WebSocket) |
main |
main.py | Entry point โ wires all components, CLI options, shutdown |
3. Installation & Setup
Prerequisites
- Python 3.10+
- LimaCharlie account with an organization and API key
- Gemini CLI installed (primary LLM) โ
sudo npm install -g @google/gemini-cli - Ollama (optional fallback LLM) โ
curl -fsSL https://ollama.ai/install.sh | sh
Note: You may need to runhash -ror start a new terminal session if theollamacommand is not immediately found. - Note: Node.js and NPM are required to install the Gemini CLI. The dashboard itself is pure Python (Flask).
Quick Start
# Clone / navigate to the project
cd /home/dfusion/Documents/FusionSOC
# 1. Create your .env file from the example
cp .env.example .env
# 2. Edit .env with your credentials
# LC_OID=your-limacharlie-org-id
# LC_API_KEY=your-api-key
# DASHBOARD_SECRET=random-secret-string
# 3. Activate the virtual environment
source venv/bin/activate
# 4. Launch FusionSOC
python main.py
The dashboard will start at http://localhost:5000. The detection poller begins immediately,
pulling the last 24 hours of detections as backfill.
CLI Options
| Flag | Description |
|---|---|
--config / -c |
Path to a custom config.yaml file (default: ./config.yaml) |
--env / -e |
Path to a custom .env file (default: ./.env) |
--no-poll |
Disable detection polling โ dashboard only mode |
--no-dashboard |
Disable web dashboard โ headless poller mode |
--port / -p |
Override the dashboard port (default: 5000) |
LimaCharlie API Key Permissions
Your API key must have the following permissions:
insight.det.list โ Fetch detections
insight.evt.get โ Fetch historical events
sensor.list โ List and export sensors
sensor.task โ Send commands to sensors (isolate, kill, etc.)
sensor.tag โ Add/remove sensor tags
dr.list โ List Detection & Response rules
org.get โ Get organization info
hive.* โ Access Hive records (D&R rules, FP rules)
4. Configuration Reference
All configuration lives in config.yaml. Environment variables referenced as
${VAR_NAME} are auto-interpolated from the .env file or system environment.
LimaCharlie Connection
limacharlie:
oid: "${LC_OID}" # Your organization ID
api_key: "${LC_API_KEY}" # REST API key
api_base: "https://api.limacharlie.io" # API base URL
Detection Polling
polling:
interval_seconds: 30 # Seconds between poll cycles
backfill_hours: 24 # Hours of historical data to pull on first start
max_detections_per_poll: 100 # Max detections per API call
AI Triage Engine
triage:
primary_llm: "gemini-cli" # Primary LLM for single-model mode
fallback_llm: "ollama" # Fallback if primary fails
ollama_model: "qwen3.5:27b" # Default Ollama backup model
ollama_host: "http://localhost:11434" # Ollama API endpoint
auto_triage: true # Automatically triage new detections
confidence_threshold: 0.7 # Minimum confidence for auto-actions
max_concurrent_triages: 5 # Thread pool size
# Multi-Model Voting System (v1.0)
voting_enabled: true # Enable 3-model parallel voting
voting_models: # Models that vote on each detection
- "qwen3.5:4b" # Fast first opinion
- "qwen3:4b" # Deep technical analysis
- "deepseek-r1:8b" # Alternative model
Response Automation
response:
auto_respond: false # Master switch for auto-response (DISABLED by default)
auto_isolate_on_critical: false # Auto-isolate on critical + true_positive
auto_tag: true # Always tag investigated sensors
tag_prefix: "fusionsoc" # Prefix for auto-applied tags
manual_approval_required: true # Queue destructive actions for approval
Setting auto_respond: true AND auto_isolate_on_critical: true will cause
FusionSOC to automatically network-isolate sensors when a critical severity + true
positive verdict is returned by the AI. Only enable this after thoroughly validating AI verdict accuracy
in your environment.
Dashboard & Database
dashboard:
host: "0.0.0.0"
port: 5000
secret_key: "${DASHBOARD_SECRET}"
database:
path: "./fusionsoc.db" # SQLite database file path
logging:
level: "INFO" # DEBUG, INFO, WARNING, ERROR
file: "./fusionsoc.log" # Log file path
5. LimaCharlie API Client
The LCClient class (fusionsoc/lc_client.py) wraps the LimaCharlie REST API with
automatic JWT authentication, error handling, and helper methods. All endpoints are prefixed with the
configured api_base.
Authentication
JWT tokens are obtained by POSTing your OID + API secret to https://jwt.limacharlie.io. Tokens
are cached and automatically refreshed 60 seconds before expiry (~1 hour lifespan).
Available Methods
| Method | LC Endpoint | Description |
|---|---|---|
get_detections() |
GET /insight/{oid}/detections | Fetch detections with cursor pagination, time range, category, and sensor filters |
get_detection_by_id() |
GET /insight/{oid}/detections/{atom} | Fetch a single detection by its detect ID |
get_detection_breakdown() |
GET /insight/{oid}/detections/breakdown | Category-level detection counts over a time range |
get_detection_stats() |
GET /insight/{oid}/detections/stats | Detection count timeseries (per hour/day) |
get_historic_events() |
GET /insight/{oid}/{sid} | Historical telemetry events for a sensor |
get_event_by_atom() |
GET /insight/{oid}/{sid}/{atom} | Specific event by its atom ID |
get_children_of_atom() |
GET /insight/{oid}/{sid}/{atom}/children | Child events (process tree traversal) |
export_sensors() |
POST /export/{oid}/sensors | Full sensor list with metadata and tags |
find_sensor_by_hostname() |
GET /hostnames/{oid} | Find sensors by hostname prefix search |
kill_process() |
POST /sensor_task | Kill a process on a sensor by PID |
add_sensor_tag() |
POST /sensors/{oid}/{sid}/tags | Add an investigative tag (with optional TTL) |
get_dr_rules() |
GET /hive/dr-general/{oid} | List all Detection & Response rules |
get_mitre_report() |
GET /mitre/{oid} | Generate MITRE ATT&CK coverage map |
search_object() |
GET /insight/{oid}/objects/{type} | IOC search (IP, domain, hash, etc.) |
health_check() |
Multiple | Quick health check (org info + online sensor count) |
6. Detection Poller
The poller (fusionsoc/poller.py) is a background thread that continuously queries LimaCharlie
for new detections.
Behavior
- Polling interval: configurable (default 30s). Each cycle queries
GET /insight/{oid}/detections - Cursor pagination: automatically follows
next_cursorto retrieve all new detections - Deduplication: maintains an in-memory set of seen
detect_idvalues, plus database-levelUNIQUEconstraint - Backfill: on first startup (when no poll state exists in DB), pulls the last N hours (default 24) of detections
- Resume: stores the last poll timestamp in the
poll_statetable so it resumes cleanly after restart - Callback: each new detection triggers
on_new_detection(detection_record, raw_json)which feeds the triage pipeline
7. Context Enricher
The enricher (fusionsoc/enricher.py) wraps each raw detection with surrounding context before it
reaches the AI triage engine.
Enrichment Layers
| Layer | Data Source | What's Added |
|---|---|---|
sensor |
Sensor export API (cached) | Hostname, external IP, internal IP, platform, OS, isolated status, tags, version, enrollment date |
process_tree |
Atom children API + event data | Current process (file path, command line, PID, user), parent atom, child process summary (up to 5) |
recent_events |
Historic events API | Event type distribution in a ยฑ30 minute window around the detection (e.g., "NEW_PROCESS: 10, DNS_REQUEST: 20") |
rule_info |
D&R rules Hive (cached) | Rule name, enabled status, comment, tags |
mitre_tags |
Detection rule_tags field | Extracted MITRE ATT&CK technique IDs (e.g., T1059.001) |
The sensor cache and D&R rule cache are populated on first use and can be invalidated via
enricher.invalidate_cache().
8. AI Triage Engine
The triage engine (fusionsoc/triage.py) is the analytical brain of FusionSOC. It uses a
multi-model voting system where 3 local LLMs independently analyze each detection.
๐ณ๏ธ Multi-Model Voting System
When voting is enabled (default), each detection is sent to all 3 Ollama models in parallel. Each model independently produces a verdict, severity, and confidence score. Results are tallied:
| Vote Outcome | Auto-Action |
|---|---|
| Unanimous false_positive | Recommend close case as FP |
| Unanimous true_positive | Recommend escalate to IR + isolate + collect forensics |
| Unanimous benign | Recommend close as benign |
| Majority vote | Use winning verdict, flag confidence level |
| Split vote | Flag for mandatory manual analyst review |
Every triage result includes a voting object in the triage JSON showing each model's individual
verdict, confidence, severity, and risk score for full transparency.
Fallback: Single-Model Mode
If voting is disabled (voting_enabled: false), the engine falls back to the original strategy:
- Primary: Gemini CLI (
gemini -p "...") โ cloud-based, high quality - Fallback: Ollama (
POST /api/generate) โ local, privacy-first - If both fail, the detection is marked
suspiciouswithconfidence: 0.0and flagged for manual review
Prompt Structure
The system prompt instructs the LLM to act as a senior SOC analyst at Fusion Cybersecurity. Each detection prompt includes:
- DETECTION EVENT โ rule name, category, event type, MITRE tags
- EVENT DATA โ file path, command line, PID, user, hash, registry key, IPs, domains
- SENSOR CONTEXT โ hostname, IPs, platform, online/isolated status, tags
- PROCESS TREE โ current process details, child process summary
- RECENT SENSOR EVENTS โ event type distribution in a 30-minute window
- DETECTION RULE INFO โ rule name, enabled status, comment
Triage Output Schema (JSON)
{
"severity": "critical | high | medium | low | informational",
"verdict": "true_positive | false_positive | suspicious | benign",
"confidence": 0.0 - 1.0,
"summary": "[UNANIMOUS VOTE 3/3] One-paragraph detailed analysis",
"ioc_analysis": "Explanation of why IOCs are malicious or benign",
"iocs_extracted": ["ip:1.2.3.4", "hash:abc123", "domain:evil.com"],
"mitre_techniques": ["T1059.001", "T1027"],
"recommended_actions": ["ESCALATE to IR", "Isolate sensor immediately"],
"investigation_questions": ["Was this user active at this time?"],
"false_positive_reason": null | "explanation",
"risk_score": 0 - 100,
"voting": {
"mode": "unanimous | majority | split",
"auto_action": "escalate_ir | auto_close_fp | manual_review",
"total_models": 3,
"winning_verdict": "true_positive",
"winning_count": 3,
"votes": [{"model": "llama3.1:8b", "verdict": "...", "confidence": 0.95}],
"vote_summary": ["llama3.1:8b: true_positive (critical, 95%)"]
}
}
Severity Guidelines
| Severity | Criteria |
|---|---|
| Critical | Active breach, data exfiltration, ransomware, credential theft in progress |
| High | Confirmed malicious activity, C2 communication, privilege escalation |
| Medium | Suspicious behavior needing investigation, potential lateral movement |
| Low | Minor policy violation, reconnaissance activity |
| Info | Noise, benign anomaly, known good behavior |
9. Case Management
The case manager (fusionsoc/case_manager.py) provides a full case lifecycle with automatic
creation, intelligent grouping, and SOC metrics.
Case Lifecycle
Detection Grouping
Detections are automatically grouped into an existing case if they share the same sensor ID + same category and the case was created within the last 30 minutes and is still in an active status (new, triaging, open, or investigating). If the new detection has a higher severity, the case severity is upgraded.
Database Schema
| Table | Key Fields | Purpose |
|---|---|---|
cases |
id, title, severity, status, verdict, assigned_to, summary_ai, created_at, resolved_at, detection_count | Top-level case record |
detections |
id, detect_id (unique), category, rule_name, sensor_id, hostname, severity_ai, verdict_ai, confidence_ai, raw_json, enriched_json, triage_json, case_id | Every detection record |
case_notes |
id, case_id, author, content, note_type, timestamp | Analyst notes and AI analysis |
case_actions |
id, case_id, action_type, target, status, result, executed_by, timestamp | Response actions (pending, executed, failed, rejected) |
case_timeline |
id, case_id, event_type, description, actor, timestamp | Full audit trail for every case event |
poll_state |
id, last_cursor, last_timestamp, updated_at | Tracks poller state for resume after restart |
SOC Metrics
- MTTR (Mean Time to Resolve) โ Average time from case creation to resolution
- Cases by Status โ Breakdown across lifecycle stages
- Cases by Severity โ Distribution of critical/high/medium/low/info
- Detections by Verdict โ True positive / false positive / suspicious / benign
- Open Cases โ Count of cases in new, triaging, open, or investigating status
10. Response Automation
The responder (fusionsoc/responder.py) executes containment, remediation, and smart
investigation actions through the LimaCharlie API.
Available Actions
| Action | What It Does | Trigger | Destructive? |
|---|---|---|---|
| Tag Sensor | POST /{sid}/tags?tags={tag} | Always (when auto_tag: true) |
No |
| Kill Process | os_kill_process -p {pid} | Manual execution only | ๐ด Yes |
| Smart Investigation | Queries LC historic events API based on action keywords | Approve a "recommended" action | No (read-only) |
๐ Smart Investigation System
When you approve a recommended action (e.g., "Check for lateral movement"), FusionSOC maps the action text to real LimaCharlie API investigation queries:
| Action Contains | Events Queried |
|---|---|
| "lateral" | NEW_REMOTE_THREAD, NETWORK_CONNECTIONS, NEW_PROCESS |
| "process" | NEW_PROCESS, EXISTING_PROCESS, TERMINATE_PROCESS |
| "persist" / "autorun" | REGISTRY_CREATE, NEW_AUTORUN, SCHEDULED_TASK |
| "network" | NETWORK_CONNECTIONS, DNS_REQUEST |
| "credential" | NEW_PROCESS, SENSITIVE_PROCESS_ACCESS |
| "file" | FILE_CREATE, FILE_DELETE, FILE_MODIFIED |
| "dns" | DNS_REQUEST |
| "exfil" | NETWORK_CONNECTIONS, FILE_CREATE |
| (anything else) | General event overview sweep |
Results are stored as a detailed case note with event counts, extracted details (file paths, command lines, IPs, domains), and a timeline entry.
Safety Controls
- auto_respond: false (default) โ All destructive actions are queued as "pending" and must be manually approved/rejected from the Actions page in the dashboard
- Network isolation is disabled โ The
isolate_sensor()andrejoin_sensor()methods have been intentionally removed for safety - manual_approval_required: true (default) โ Actions go to the approval queue
- Every action (executed, failed, or rejected) is logged in
case_actionswith acase_timelineaudit entry
Pipeline Tags
Every sensor processed by FusionSOC is tagged at each stage of the pipeline for full observability in the LimaCharlie console:
| Tag | Applied When | Purpose |
|---|---|---|
fusion-soc-pulled |
Detection fetched from API | Confirms sensor's detection was ingested by FusionSOC |
fusion-soc-triage |
AI triage analysis completes | Confirms AI has analyzed the detection |
fusion-soc-case |
Detection linked to a case | Confirms case management is tracking this sensor |
fusion-soc-alert |
Critical or High severity verdict | Flags high-priority sensors for immediate attention |
11. Dashboard Pages
Overview (/)
Live operational overview showing: open cases count, total detections, total cases, AI triage stats (count + errors), poller status (active/stopped, cache size), pending response actions, severity distribution bar chart, AI verdict distribution, recent 10 cases table (clickable), and recent 15 detections table.
Cases (/cases)
Filterable case list. Filters include status (new, triaging, open, investigating, contained, resolved, closed) and severity (critical, high, medium). Each row is clickable and shows ID, title, severity badge, status badge, verdict, detection count, assignee, and creation date. Hide Closed toggle โ Click "๐ซ Hide Closed" to show/hide closed and resolved cases (active by default).
Case Detail (/cases/<id>)
Full case view with: AI analysis summary (with voting results), all linked detections (with IOCs and MITRE badges), collapsible Raw Detection JSON and Triage JSON viewers, response actions table (with execute/reject buttons that trigger smart investigations), analyst notes (add new notes via textarea), and full timeline audit trail.
Detections (/detections)
Raw detection feed with filters for severity and verdict. Columns include category, rule name, hostname, event type, AI severity badge, verdict, confidence percentage, and linked case ID.
Sensors (/sensors)
Live sensor inventory pulled from the LimaCharlie API. Shows online/offline status dot, hostname, external IP, internal IP, platform icon (Windows/macOS/Linux/ChromeOS), version, isolation badge, and up to 3 tags per sensor.
Actions (/actions)
Manual approval queue for pending response actions. Approving a recommended action triggers a smart investigation that queries the LimaCharlie API and stores results as case notes. Shows action type (with icon), target, status, queued timestamp, and approve/reject buttons.
Documentation (/docs)
This page. Comprehensive reference for the entire platform.
12. REST API Reference
The dashboard exposes internal JSON API endpoints for programmatic access and integration.
| Endpoint | Method | Description |
|---|---|---|
/api/metrics |
GET | Case management metrics (counts, MTTR, severity/status/verdict breakdowns) |
/api/health |
GET | LimaCharlie connection health check (org name, sensors online/total) |
/api/detections/recent |
GET | Last 20 detections with triage results |
/api/cases/recent |
GET | Last 20 cases |
/api/poller/stats |
GET | Poller statistics (total stored, cache size, last poll timestamp, running status) |
/api/cases/{id}/status |
POST | Update case status. Body: {"status": "investigating"} |
/api/cases/{id}/assign |
POST | Assign case. Body: {"assignee": "analyst@fusion.sec"} |
/api/cases/{id}/notes |
POST | Add note. Body: {"content": "...", "author": "analyst"} |
/api/actions/{id}/execute |
POST | Approve and execute a pending response action |
/api/actions/{id}/reject |
POST | Reject a pending response action |
13. WebSocket Events
The dashboard uses Socket.IO for real-time push updates. Connect to the same host/port as the dashboard.
| Event | Direction | Payload |
|---|---|---|
status |
Server โ Client | {"message": "Connected to FusionSOC"} |
new_detection |
Server โ Client | {"detect_id", "category", "hostname", "rule_name", "severity_ai", "verdict_ai"}
|
case_update |
Server โ Client | {"id", "title"} |
14. Troubleshooting
LC health check fails on startup
Verify your LC_OID and LC_API_KEY in .env. Test with:
curl -X POST https://jwt.limacharlie.io -d '{"oid":"YOUR_OID","secret":"YOUR_KEY"}'. A valid
response returns a JWT token.
No detections appearing
- Check the poller is running (dashboard overview shows "๐ข Active")
- Verify your org has D&R rules generating detections
- Check
fusionsoc.logfor API errors - Ensure the API key has
insight.det.listpermission
AI triage returning errors
- Verify Gemini CLI is installed:
which gemini - If using Ollama fallback, verify it's running:
curl http://localhost:11434/api/tags - Check
fusionsoc.logfor LLM error details - The fallback will auto-set
verdict: suspiciouswithconfidence: 0.0if both LLMs fail
Dashboard not loading
- Check port conflicts:
ss -tlnp | grep 5000 - Try a different port:
python main.py -p 8080 - Check
fusionsoc.logfor Flask startup errors
Database reset
To start fresh, delete the SQLite database file: rm fusionsoc.db. It will be recreated
automatically on next startup with empty tables.
For issues, feature requests, or to report false positive patterns, contact Fusion Cybersecurity.