Autonomous AI-powered SOC investigation platform. A 4-hour manual investigation in 100 seconds — 6 specialized AI agents, ReAct kill chain reconstruction, and Splunk-native AI validation.
- Devpost submission: https://devpost.com/software/splunk-sentinel
- Demo video: https://youtu.be/vdQYQY1cXFA?si=Vgykh75108fiCi5D
- Architecture: architecture_diagram.md
- Splunk SDK usage: SPLUNK_SDK_USAGE.md
Demo video: https://youtu.be/vdQYQY1cXFA?si=Vgykh75108fiCi5D
Required dependencies: Splunk Enterprise + botsv3, Python 3.12, Node 20, OpenAI API key, Qdrant Cloud (free tier)
Optional (graceful fallback if missing):
- VirusTotal API key — threat intel shows "unavailable", pipeline continues
- AbuseIPDB API key — same fallback as above
- Langfuse account — falls back to hardcoded prompts, pipeline unaffected
- LangSmith API key — tracing disabled, pipeline unaffected
- Supabase — recommended for full report persistence, investigation history, analyst feedback, and reproducible report review. Without Supabase, a live investigation may run but persisted history and report storage will be unavailable.
Testing / API cost note: Splunk Sentinel is open source and free to review, test, and use. Running the full AI investigation workflow locally requires the tester to provide their own OpenAI API key. The project itself does not charge any fee, does not require proprietary hardware, and uses
gpt-4o-minito keep per-investigation cost low. The public demo video shows the end-to-end workflow for reviewers who choose not to run the full local Splunk/OpenAI/Qdrant stack.
Platform note: Shell commands below use Windows syntax. On macOS/Linux replace
.venv\Scripts\activatewithsource .venv/bin/activateandcd ..\frontendwithcd ../frontend.
1. Clone and install
git clone https://github.com/Asembris/splunk-sentinel.git
cd splunk-sentinel
# Backend
cd backend
python -m venv .venv
.venv\Scripts\activate # Windows — see platform note above
pip install -r requirements.txt
# Frontend
cd ../frontend
npm install2. Configure .env
Use backend/app/.env.example and set:
SPLUNK_HOST=localhost
SPLUNK_PORT=8089
SPLUNK_USERNAME=your_splunk_username
SPLUNK_PASSWORD=your_splunk_password
OPENAI_API_KEY=sk-your_openai_api_key
QDRANT_URL=https://your-cluster.qdrant.io
QDRANT_API_KEY=your_qdrant_api_key
VIRUSTOTAL_API_KEY=your_virustotal_api_key
ABUSEIPDB_API_KEY=your_abuseipdb_api_key
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_KEY=your_supabase_service_key
LANGCHAIN_API_KEY=your_langsmith_api_key
LANGCHAIN_TRACING_V2=true
LANGCHAIN_PROJECT=splunk-sentinel
LANGFUSE_PUBLIC_KEY=your_langfuse_public_key
LANGFUSE_SECRET_KEY=your_langfuse_secret_key
LANGFUSE_BASE_URL=https://cloud.langfuse.com3. Create Supabase table:
For the full persisted demo/history/report workflow, complete the Supabase setup below.
Run supabase_schema.sql in your Supabase SQL Editor:
- Go to your Supabase project dashboard
- Click SQL Editor -> New Query
- Paste the contents of
supabase_schema.sql - Click Run
- Expected: table created with 0 rows
4. Install Splunk app (one click):
Download sentinel.spl from the repo root and install:
- Open Splunk UI at
http://localhost:8000 - Apps -> Manage Apps -> Install app from file
- Upload
sentinel.spl - Check "Upgrade app" if prompted
- Restart Splunk when prompted
This automatically creates:
sentinel_findingsindexsentinel_actionsindex- MLTK
authorize.confcapabilities - Native Splunk dashboard at
/app/splunk_sentinel_app/sentinel_dashboard
5. Ingest RAG knowledge base (run once)
# continuing from frontend/ after step 1
cd ../backend
.venv\Scripts\activate
python -m app.rag.ingest6. Start backend
# from repo root — open a new terminal for this long-running process
cd backend
.venv\Scripts\activate
uvicorn app.main:app --host 0.0.0.0 --port 8001 --reload7. Start frontend
# from repo root — open a new terminal for this long-running process
cd frontend
npm run dev
# http://localhost:51738. Verify health
GET http://localhost:8001/api/health
Expected:
{
"status": "ok",
"splunk_connected": true,
"splunk_version": "10.2.2",
"prompt_versions": {
"triage-agent": {"name": "triage-agent", "version": 1, "label": "production"},
"synthesis-narrative": {"name": "synthesis-narrative", "version": 1, "label": "production"},
"containment-refinement": {"name": "containment-refinement", "version": 1, "label": "production"}
},
"promptops": "langfuse"
}Current
/api/healthbehavior:promptopscurrently returns"langfuse"unconditionally. If Langfuse credentials are missing or Langfuse is unreachable,prompt_versionsentries may be empty objects while the prompt loader internally falls back to memory cache or built-in hardcoded prompts. The health endpoint exposes core prompt metadata only; it should not be read as a complete list of every prompt or as a full PromptOps fallback-state indicator.
9. Run your first investigation
POST http://localhost:8001/api/investigate
{
"trigger": "Suspicious outbound requests to AWS metadata endpoint detected from internal web server. Possible SSRF attack leading to IAM credential exposure.",
"investigation_id": "judge-test-001"
}Typical response includes:
classification— attack type (e.g. APT, RANSOMWARE, INSIDER_THREAT, or UNKNOWN)investigation_confidence— numeric confidence scorekill_chain_stages— reconstructed kill chain stagesttp_mappings— mapped MITRE ATT&CK techniquescontainment_plan— phased IR containment plan
10. Run the test suite
# from repo root
cd backend
.venv\Scripts\activate
python -m pytest tests/ --ignore=tests/eval/ -vExpected: 425 passed, 0 failed
SOC analysts investigating APT incidents spend 4+ hours manually pivoting between data sources — running 15-20 sequential Splunk queries, each informed by the last. During this time:
- Alert fatigue causes critical kill chain events to be missed
- Manual correlation across 2M+ events is error-prone and slow
- Context switching between tools breaks investigative flow
- Dwell time increases — attackers operate undetected for longer
The BOTS v3 dataset demonstrates this problem exactly: 2,083,056 log events across 20 sourcetypes. A human analyst needs 3-4 hours to reconstruct the kill chain. Splunk Sentinel does it in ~100 seconds.
graph TD
A[🔔 Alert Trigger<br/>Splunk Webhook / User Prompt] --> B
subgraph TRIAGE ["⚡ Phase 1 — Triage"]
B[TriageAgent<br/>Classification · Confidence · SPL Routing]
end
subgraph RECONSTRUCTION ["🔍 Phase 2 — Reconstruction ReAct Loop"]
C[ReconstructionAgent<br/>Iterative SPL Generation · Kill Chain Building<br/>Self-Correction · Patient Zero · Blast Radius]
end
subgraph PARALLEL ["⚡ Phase 3 — Parallel Enrichment"]
D[ThreatIntelAgent<br/>VirusTotal · AbuseIPDB<br/>IP Reputation]
E[TTPAgent<br/>MITRE ATT&CK RAG<br/>697 Techniques · CVE Lookup]
end
subgraph SYNTHESIS ["📊 Phase 4 — Synthesis"]
F[SynthesisAgent<br/>RAG Retrieval · Evidence Citation<br/>Confidence Scoring · Report Generation]
end
subgraph REPORTING ["📋 Phase 5 — Reporting"]
RA[ReportAgent<br/>PDF · Supabase · Splunk Write-back<br/>4-Tier Confidence Ladder]
end
B -->|APT/Ransomware/Insider| C
B -->|UNKNOWN| Z[🔚 END — Escalate to Human]
C --> D
C --> E
D --> F
E --> F
F --> RA[ReportAgent<br/>PDF Generation · Supabase · Splunk Write-back]
RA --> G[📄 Complete Investigation Package<br/>PDF Report · Notable Event · Analyst Feedback]
style TRIAGE fill:#1e3a5f,stroke:#3b82f6
style RECONSTRUCTION fill:#1e3a5f,stroke:#3b82f6
style PARALLEL fill:#1a2e1a,stroke:#10b981
style SYNTHESIS fill:#2d1b1b,stroke:#ef4444
style REPORTING fill:#1a1a2e,stroke:#8b5cf6
sequenceDiagram
participant T as Trigger
participant R as ReconstructionAgent
participant S as Splunk (botsv3)
participant L as LLM (gpt-4o-mini)
participant Q as Qdrant RAG
participant G as SPL Guardrail
T->>R: AgentState (classification, indicators)
loop ReAct Iterations (max 3)
R->>G: Validate SPL query
G-->>R: ✅ Approved / ❌ Blocked
R->>S: Execute SPL query
S-->>R: Telemetry results
R->>L: Reason: what did we find?<br/>Act: what to query next?
L-->>R: ReActObservation<br/>(new_stages, gaps, next_queries)
R->>R: Update kill chain stages
R->>R: Compute confidence score
alt confidence >= 0.85 OR stages >= 5
R->>R: Terminate loop
end
end
R->>L: Synthesis: produce final report
L-->>R: ReconstructionResult
R->>Q: Retrieve MITRE technique details
Q-->>R: Enriched TTP mappings
R-->>T: kill_chain, patient_zero, blast_radius
graph LR
subgraph SOURCES ["📚 Knowledge Sources"]
A[MITRE ATT&CK<br/>Enterprise STIX<br/>697 techniques]
B[CVE / NVD<br/>Filtered to botsv3<br/>attack surface]
C[IR Playbooks<br/>APT · Ransomware<br/>Insider Threat]
D[botsv3 Notes<br/>Manual forensic<br/>ground truth]
end
subgraph EMBEDDING ["🔢 Embedding Pipeline"]
E[text-embedding-3-large<br/>3072 dimensions<br/>OpenAI]
end
subgraph STORE ["🗄️ Qdrant Cloud"]
F[mitre_attack<br/>697 techniques]
G[cve_nvd<br/>botsv3 attack surface]
H[ir_playbooks<br/>APT · Ransomware · Insider]
I[botsv3_investigation<br/>forensic ground truth]
end
subgraph RETRIEVAL ["🔍 Parallel Retrieval"]
J[retrieve_for_synthesis<br/>4 collections in parallel<br/>threshold 0.45]
end
A --> E --> F --> J
B --> E --> G --> J
C --> E --> H --> J
D --> E --> I --> J
J --> K[SynthesisAgent<br/>RAG-grounded report]
Evidence integrity note: Kill-chain reconstruction is driven by Splunk telemetry and guarded SPL execution. The
botsv3_investigationRAG collection is retrieved only during final synthesis to support explanation, remediation, and report context after reconstruction is complete.
stateDiagram-v2
[*] --> triage_agent
triage_agent --> reconstruction_agent: APT/Ransomware/Insider
triage_agent --> END: UNKNOWN / low confidence
reconstruction_agent --> threat_intel_agent: parallel fan-out
reconstruction_agent --> ttp_agent: parallel fan-out
threat_intel_agent --> synthesis_agent: merge
ttp_agent --> synthesis_agent: merge
synthesis_agent --> report_agent: final_report populated
report_agent --> END: PDF · Supabase · Splunk write-back
note right of report_agent
ReportLab PDF generation
Supabase persistence
Splunk notable event write-back
4-tier confidence ladder
end note
note right of reconstruction_agent
ReAct loop
max 3 iterations
SPL guardrail on every query
end note
note right of triage_agent
3-layer SPL guardrail
Layer 1: deterministic 0ms
Layer 2: index authorization
Layer 3: audit logging
end note
flowchart TD
Q[SPL Query] --> L1
subgraph L1 ["Layer 1 — Deterministic 0ms"]
L1C{Contains blocked terms?<br/>DELETE · DROP · outputlookup<br/>sendemail · _internal}
end
subgraph L2 ["Layer 2 — Index Authorization"]
L2C{Targets only<br/>index=botsv3?}
end
subgraph L3 ["Layer 3 — Audit Log"]
L3C[Write to audit log<br/>timestamp · query · result]
end
L1C -->|YES| BLOCKED1[🚫 BLOCKED<br/>Reason logged]
L1C -->|NO| L2C
L2C -->|NO| BLOCKED2[🚫 BLOCKED<br/>Out of scope]
L2C -->|YES| L3C
L3C --> EXEC[✅ Execute against Splunk]
EXEC --> RESULTS[Return results to agent]
graph TD
R[ReportAgent<br/>Investigation persisted] --> CE
R --> ME
subgraph POST ["Post-Pipeline Services (analyst-triggered)"]
CE[containment_engine<br/>Phase execution + rollback]
CC[containment_chat<br/>ContainmentRefinementAgent<br/>ReAct tool calling]
CV[containment_verifier<br/>SPL verification of effects]
DG[detection_gap_analyzer<br/>MITRE coverage analysis]
ME[mltk_enrichment<br/>Async MLTK ai command validation]
end
CE --> CV
CE --> CC
R --> DG
style POST fill:#1a1a2e,stroke:#8b5cf6
ReconstructionAgent runs a bounded ReAct loop (max 3 iterations) to reason over telemetry, issue next SPL queries, self-correct query failures, and converge on a complete kill chain with patient zero and blast radius.
Deterministic 5-factor confidence, not LLM-generated:
- Kill chain completeness:
0.35 - Evidence variety:
0.30 - Patient zero identification:
0.10 - External indicator evidence:
0.10 - Blast radius assessment:
0.15
Includes weakest-factor callout plus a concrete recommendation.
After persistence, Splunk MLTK ai validates MITRE mappings asynchronously (~30s post-investigation). Validation runs in parallel and never blocks pipeline SLO. Qdrant/MLTK agreement boosts confidence using Qdrant 60% + MLTK 40%. UI updates via polling. MLTK validation runs as a post-investigation background enrichment step when Splunk MLTK 5.7.4 and the configured openai_sentinel connection are available. Techniques show MLTK Validated, MLTK Review, or NOT RUN. NOT RUN indicates enrichment has not completed or was not available for that investigation.
3-phase IR plan (IMMEDIATE, SHORT TERM, REMEDIATION) with analyst edits, SSE execution, and rollback via reversal SPL. containment_verifier proves measurable effect with deterministic before/after SPL counts and verdicts:
VERIFIED_EFFECTIVEPARTIAL_EFFECTVERIFICATION_FAILEDROLLBACK_RECOMMENDED
ContainmentRefinementAgent supports natural-language plan edits with ReAct tool calling, bulk operations, RFC1918 validation, deduplication, phase targeting, and conversation memory. Uses fetch ReadableStream SSE for Safari compatibility.
Compares MITRE techniques against existing Splunk saved searches, identifies uncovered techniques, generates recommended detection SPL (LLM + templates), and deploys in one click through Splunk SDK. Includes cache, duplicate checks, and guardrails.
Before/After Coverage Improvement: After deploying a generated saved search, analysts can click Re-run Coverage to force-refresh the gap analysis (force_refresh=true). The UI shows a before/after panel with coverage percentage before Sentinel, coverage percentage after deployment, delta in percentage points, newly covered techniques, gaps closed, and saved searches checked before and after. This is the closed-loop SOC improvement story.
Core production prompts are managed in Langfuse (v1), with production/staging labels, startup validation, 5-minute TTL caching, memory fallback, and hardcoded fallback to prevent pipeline outages.
ThreatIntelAgent and TTPAgent run in parallel after reconstruction, reducing total latency versus sequential enrichment.
Synthesis pulls from Qdrant (697 MITRE + 50 CVEs + 15 IR playbooks) to ground techniques, recommendations, and contextual explanations.
Every SPL query is recorded in a SHA-256 chain. Integrity is verifiable per investigation via API.
When configured, LangSmith traces LLM calls. Langfuse manages prompt versions. Cost is approximately $0.009 per investigation with gpt-4o-mini exclusively.
The investigation graph uses AsyncSqliteSaver to checkpoint state at every node completion, keyed by investigation_id as thread_id. If the backend restarts mid-investigation, the graph resumes from the last completed node. Completed investigations are resumable via POST /api/investigations/{id}/resume. Check checkpoint status via GET /api/investigations/{id}/checkpoint-status. Backed by a local SQLite database at backend/checkpoints.db — suitable for single-node demo environments.
| Agent | Role | Key Logic |
|---|---|---|
| TriageAgent | Classification, severity, SPL routing | 3-layer guardrail, UNKNOWN routing |
| ReconstructionAgent | Kill chain, patient zero, blast radius | ReAct max 3 iter, SPL self-correction |
| ThreatIntelAgent | IP reputation | VirusTotal + AbuseIPDB parallel, RFC1918 filter |
| TTPAgent | MITRE mapping + MLTK validation | Qdrant RAG + async MLTK enrichment |
| SynthesisAgent | Report generation | 4 parallel LLM calls, graceful degradation |
| ReportAgent | PDF, Supabase, Splunk write-back | MLTK task fire, containment persistence |
| Service | Trigger | Role |
|---|---|---|
| containment_engine | Analyst executes phase | SPL execution, sentinel_actions write |
| containment_chat | Analyst chat message | ContainmentRefinementAgent ReAct |
| containment_verifier | After action executes | SPL before/after verification |
| detection_gap_analyzer | Analyst opens gaps panel | MITRE coverage vs saved searches |
| mltk_enrichment | After investigation persists | Async MLTK ai command TTP validation |
Configure Splunk alert actions to call Sentinel for autonomous investigations from detections.
Completed investigations are written back to index=sentinel_findings.
MLTK 5.7.4 + PSC 4.3.2 with Connection Management (openai_sentinel, gpt-4o-mini):
| makeresults count=1
| eval evidence="..."
| ai connection="openai_sentinel"
prompt="Validate MITRE technique: {qdrant_technique}..."
Results enrich report content asynchronously after investigation completion.
One-click deployment creates Splunk saved searches:
| rest /services/saved/searches
| where match(title, "Sentinel")
| table title, updated
Every action execution and verification is auditable:
index=sentinel_actions earliest=0
| table investigation_id, action_type, target,
status, executed_at, verification_verdict
| sort -executed_at
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/investigate |
Start a new investigation (JSON/SSE) |
POST |
/api/webhook/splunk |
Splunk autonomous trigger |
GET |
/api/webhook/splunk/test |
Webhook connectivity test |
GET |
/api/health |
Health and Splunk connectivity |
GET |
/api/investigations/history |
Investigation history with pagination and search |
GET |
/api/investigations/{id} |
Investigation details |
POST |
/api/investigations/{id}/feedback |
Analyst feedback |
GET |
/api/investigations/{id}/report/pdf |
Download PDF |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/investigations/{id}/confidence-breakdown |
Explainable confidence factors |
GET |
/api/investigations/{id}/ttp-enrichment |
Async MLTK enrichment status/results |
GET |
/api/investigations/{id}/detection-gaps |
MITRE coverage analysis |
POST |
/api/investigations/{id}/detection-gaps/deploy |
Deploy saved search |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/investigations/{id}/containment-plan |
Load plan |
GET |
/api/investigations/{id}/containment-plan/execute |
SSE stream for phase execution (EventSource / browser) |
POST |
/api/investigations/{id}/containment-plan/execute |
Execute phase (non-browser clients) |
POST |
/api/investigations/{id}/containment-plan/rollback |
Rollback action |
GET |
/api/investigations/{id}/containment-plan/chat/init |
Init chat |
POST |
/api/investigations/{id}/containment-plan/chat |
Refinement chat |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/audit-log |
Full audit log entries |
GET |
/api/audit-log/verify/{id} |
Verify audit chain for investigation |
GET |
/api/audit-log/verify-latest |
Verify latest investigation |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/investigations/{id}/checkpoint-status |
Check if checkpoint exists and investigation completion state |
POST |
/api/investigations/{id}/resume |
Resume investigation from last checkpoint |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/slo/status |
Pipeline SLO and latency metrics |
15 golden test cases covering APT, ransomware, insider threat, UNKNOWN escalation, and hallucination traps. Results vary based on environment and model temperature. Re-run offline evals with:
python -m pytest tests/eval/ -vRequires live Splunk, running backend, and OPENAI_API_KEY configured.
425 passing backend tests including parametrized expansions across guardrails, reconstruction, containment, detection gap analyzer, confidence breakdown, containment verifier, API contracts, audit, parallel agents, schema, synthesis, and trigger categorization.
Run with python -m pytest tests/ --ignore=tests/eval/ -v.
| Step | Latency | Tokens | Cost |
|---|---|---|---|
| triage_agent | 27.3s | 3.5K | ~$0.001 |
| reconstruction_agent (3 ReAct iters) | 70.1s | 40.6K | ~$0.006 |
| threat_intel_agent | 0.4s | — | — |
| ttp_agent | 3.3s | — | — |
| synthesis_agent | 9.9s | 6.3K | ~$0.001 |
| report_agent | ~5s | — | — |
| Total | ~100s | ~50.4K | ~$0.009 |
The investigation agent operates in strict read-only mode against
index=botsv3 exclusively. Three layers of protection enforce this:
Layer 1 — Deterministic keyword blocking (0ms, zero LLM calls)
Blocked terms: | delete, delete-index, | outputlookup overwrite=true,
| sendemail, DROP, TRUNCATE, index=_internal, index=_audit
Layer 2 — Index authorization
Every SPL query is validated to target only index=botsv3. Queries
targeting production indexes, internal Splunk indexes, or customer
data are blocked before execution.
Layer 3 — Immutable audit log
Every query attempt (whether blocked or executed) is timestamped and
logged with: timestamp, investigation_id, query, layer1_result,
layer2_result, executed, results_count. This log cannot be
modified by the agent.
Investigations with reconstruction_confidence < 0.5 or
severity = CRITICAL automatically set escalate_to_human = True.
The system never produces a high-confidence report from low-quality
evidence — it escalates instead.
Every SPL query attempt — whether blocked or executed — is recorded as a tamper-evident entry in a SHA-256 hash chain. Each entry contains:
prev_hash— hash of the previous entry (genesis:"0"*64)entry_hash— SHA-256 ofprev_hash + canonical(entry content)correction_attempts— number of LLM self-correction rewriteswas_corrected— whether the query was rewritten before executionrows_returned— result count for executed queries
Modifying any entry invalidates all subsequent hashes, making
tampering immediately detectable. The GET /api/audit-log/verify/{id} and GET /api/audit-log/verify-latest
endpoints provide real-time chain integrity verification.
When an investigation completes, ReportAgent writes a structured
notable event to index=sentinel_findings via the Splunk Python
SDK. The event includes the full kill chain summary, confidence
tier, patient zero, and immediate recommended actions — making
Sentinel findings searchable in Splunk alongside native alerts:
index=sentinel_findings sourcetype="sentinel:investigation"
| table investigation_id, classification, confidence_tier,
kill_chain_summary, patient_zero_ip, severity
The system is evaluated against the Boss of the SOC v3 dataset — a realistic APT simulation used in Splunk .conf competitions.
- Total events: 2,083,056
- Sourcetypes: 20 (stream:http, stream:dns, WinEventLog:Security, osquery, syslog, ...)
- Attack window: 2018-08-20 to 2019-09-19
- Peak hour: 2018-08-20 15:00 (443,808 events)
timeline
title botsv3 APT Attack Timeline
section 2018-08-20
11h00 : Initial Access
: 54.67.127.227 to 172.16.0.178
: /forumdisplay.php exploitation
: T1190
11h05 : SSRF Exploitation
: 172.16.0.127 to 169.254.169.254
: /latest/meta-data/iam/security-credentials/
: T1552.005
11h06 : Credential Theft
: EC2InstanceRole exfiltrated
: 73 metadata queries
: T1528
11h15 : Execution
: cmd.exe x1091, WMIC.exe x536
: reg.exe x523 via EventCode 4688
: T1059.003 and T1047
12h10 : Defense Evasion
: EventCode 1102 on BSTOLL-L
: Security log cleared
: T1070.001
| IOC | Value | Role |
|---|---|---|
| External attacker IPs | 54.67.127.227, 184.85.20.125, 23.73.195.90 | Initial access |
| Internal SSRF source | 172.16.0.127, 172.31.12.76 | Compromised web server |
| Metadata endpoint | 169.254.169.254 | AWS credential theft target |
| Metadata URI | /latest/meta-data/iam/security-credentials/EC2InstanceRole | Stolen credential path |
| Compromised host | BSTOLL-L | EventCode 1102 — log cleared |
| Compromised account | BSTOLL | Admin privileges |
| Dominant EventCodes | 5156 (11,501), 4688 (7,427), 4673 (4,122) | Key investigation signals |
Note: This project requires Splunk Enterprise with the botsv3 dataset. If you cannot run it locally, the demo video shows the complete investigation flow end to end.
Demo video: https://youtu.be/vdQYQY1cXFA?si=Vgykh75108fiCi5D
Platform note: Commands below use Windows syntax. On macOS/Linux replace
.venv\Scripts\activatewithsource .venv/bin/activateand path separators accordingly.
git clone https://github.com/Asembris/splunk-sentinel.git
cd splunk-sentinelcd backend
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txtcd ../frontend
npm installCreate backend/app/.env from backend/app/.env.example with:
SPLUNK_HOSTSPLUNK_PORTSPLUNK_USERNAMESPLUNK_PASSWORDOPENAI_API_KEYQDRANT_URLQDRANT_API_KEYVIRUSTOTAL_API_KEYABUSEIPDB_API_KEYSUPABASE_URLSUPABASE_SERVICE_KEYLANGCHAIN_API_KEYLANGCHAIN_TRACING_V2LANGCHAIN_PROJECTLANGFUSE_PUBLIC_KEYLANGFUSE_SECRET_KEYLANGFUSE_BASE_URL
For the full persisted demo/history/report workflow, complete the Supabase setup below.
Run supabase_schema.sql in your Supabase SQL Editor:
- Go to your Supabase project at supabase.com/dashboard
- SQL Editor -> New Query
- Paste the full contents of
supabase_schema.sql - Click Run
Download sentinel.spl from the repo root and install:
- Open Splunk UI at
http://localhost:8000 - Apps -> Manage Apps -> Install app from file
- Upload
sentinel.spl - Check "Upgrade app" if prompted
- Restart Splunk when prompted
This automatically creates:
sentinel_findingsindexsentinel_actionsindex- MLTK
authorize.confcapabilities - Native Splunk dashboard at
/app/splunk_sentinel_app/sentinel_dashboard
# continuing from frontend/ after step 3
cd ../backend
.venv\Scripts\activate
python -m app.rag.ingest# from repo root — open a new terminal for this long-running process
cd backend
.venv\Scripts\activate
uvicorn app.main:app --host 0.0.0.0 --port 8001 --reload# from repo root — open a new terminal for this long-running process
cd frontend
npm run devOpen: http://localhost:5173
curl http://localhost:8001/api/healthExpect:
"status": "ok""splunk_connected": true"splunk_version": "10.2.2""promptops": "langfuse"- prompt versions metadata
curl -X POST http://localhost:8001/api/investigate ^
-H "Content-Type: application/json" ^
-d "{\"trigger\":\"Suspicious outbound requests to AWS metadata endpoint detected from internal web server. Possible SSRF attack leading to IAM credential exposure.\",\"investigation_id\":\"judge-test-001\"}"Typical response includes:
classification— attack type (e.g. APT, RANSOMWARE, INSIDER_THREAT, or UNKNOWN)investigation_confidence— numeric confidence scorekill_chain_stages— reconstructed kill chain stagesttp_mappings— mapped MITRE ATT&CK techniquescontainment_plan— phased IR containment plan
# from repo root
cd backend
.venv\Scripts\activate
python -m pytest tests/ --ignore=tests/eval/ -vExpected: 425 passed, 0 failed
| Layer | Technology | Version | Purpose |
|---|---|---|---|
| Agent Orchestration | LangGraph | 0.2 | State machine + parallel fan-out |
| LLM | GPT-4o-mini | OpenAI | SPL generation, reasoning, synthesis |
| Security Platform | Splunk Enterprise | 10.2.2 | Log ingestion + search execution |
| Dataset | BOTS v3 | — | 2,083,056 events |
| Vector Store | Qdrant Cloud | 1.11 | RAG retrieval |
| Embeddings | text-embedding-3-large | 3072 dims | Semantic search |
| Backend | FastAPI | 0.115 | REST API + SSE streaming |
| Frontend | React 18 + Vite | React 18 / Vite | Real-time dashboard |
| Persistence | Supabase | PostgreSQL | Investigation storage (JSONB) |
| PromptOps | Langfuse | 3.14.6 | Prompt versioning + validation |
| AI Toolkit | Splunk MLTK | 5.7.4 | Native Splunk AI command |
| ML Runtime | Python for Scientific Computing | 4.3.2 | MLTK dependency |
| Checkpointing | SQLite via AsyncSqliteSaver | — | Durable graph state per investigation |
| Tracing | LangSmith | — | End-to-end LLM traces |
- FINDINGS.md — 10 technical findings including MLTK latency analysis, SPL guardrail design, Langfuse PromptOps, and containment verification
- SPLUNK_SDK_USAGE.md — Complete Splunk SDK integration guide including SDK reconnect, saved-search deployment, before/after coverage, MLTK syntax, and local certificate notes
- architecture_diagram.md — System architecture overview
- Public open-source repository with a root
LICENSEfile. - Architecture diagram included in
architecture_diagram.md. - Runtime Splunk integration through the Splunk Python SDK, guarded SPL execution, saved-search deployment, and write-back to
sentinel_findings/sentinel_actions. - Splunk AI capability path documented through asynchronous MLTK
aienrichment when Splunk MLTK and theopenai_sentinelconnection are configured. - The submitted project was substantially developed and polished during the hackathon period, as reflected in commit history.
MIT — see LICENSE
- Splunk BOTS v3 — Ryan Kovar et al.
- MITRE ATT&CK — MITRE Corporation
- LangGraph — LangChain
- Qdrant — Vector similarity search
- DeepEval — LLM evaluation
- vis-network — Graph visualization
- Langfuse — Prompt management
- Supabase — Investigation persistence
- Splunk MLTK — AI Toolkit integration