security-detections-mcp 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +344 -47
- package/dist/db.d.ts +76 -2
- package/dist/db.js +644 -15
- package/dist/index.js +701 -12
- package/dist/indexer.d.ts +7 -1
- package/dist/indexer.js +131 -5
- package/dist/parsers/elastic.d.ts +2 -0
- package/dist/parsers/elastic.js +245 -0
- package/dist/parsers/kql.d.ts +2 -0
- package/dist/parsers/kql.js +348 -0
- package/dist/parsers/sigma.js +310 -0
- package/dist/parsers/splunk.js +151 -1
- package/dist/parsers/story.d.ts +2 -0
- package/dist/parsers/story.js +31 -0
- package/dist/types.d.ts +97 -1
- package/dist/types.js +1 -1
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
# Security Detections MCP
|
|
2
2
|
|
|
3
|
-
An MCP (Model Context Protocol) server that lets LLMs query a unified database of **Sigma
|
|
3
|
+
An MCP (Model Context Protocol) server that lets LLMs query a unified database of **Sigma**, **Splunk ESCU**, **Elastic**, and **KQL** security detection rules.
|
|
4
4
|
|
|
5
|
-
[](https://cursor.com/en/install-mcp?name=security-detections&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInNlY3VyaXR5LWRldGVjdGlvbnMtbWNwIl0sImVudiI6eyJTSUdNQV9QQVRIUyI6Ii9wYXRoL3RvL3NpZ21hL3J1bGVzLC9wYXRoL3RvL3NpZ21hL3J1bGVzLXRocmVhdC1odW50aW5nIiwiU1BMVU5LX1BBVEhTIjoiL3BhdGgvdG8vc2VjdXJpdHlfY29udGVudC9kZXRlY3Rpb25zIiwiU1RPUllfUEFUSFMiOiIvcGF0aC90by9zZWN1cml0eV9jb250ZW50L3N0b3JpZXMiLCJFTEFTVElDX1BBVEhTIjoiL3BhdGgvdG8vZGV0ZWN0aW9uLXJ1bGVzL3J1bGVzIiwiS1FMX1BBVEhTIjoiL3BhdGgvdG8va3FsLXJ1bGVzIn19)
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
- **Unified Search** - Query
|
|
10
|
-
- **Full-Text Search** - SQLite FTS5 powered search across names, descriptions, queries, and
|
|
11
|
-
- **MITRE ATT&CK Mapping** - Filter detections by technique ID
|
|
9
|
+
- **Unified Search** - Query Sigma, Splunk ESCU, Elastic, and KQL detections from a single interface
|
|
10
|
+
- **Full-Text Search** - SQLite FTS5 powered search across names, descriptions, queries, MITRE tactics, CVEs, process names, and more
|
|
11
|
+
- **MITRE ATT&CK Mapping** - Filter detections by technique ID or tactic
|
|
12
|
+
- **CVE Coverage** - Find detections for specific CVE vulnerabilities
|
|
13
|
+
- **Process Name Search** - Find detections that reference specific processes (e.g., powershell.exe, w3wp.exe)
|
|
14
|
+
- **Analytic Stories** - Query by Splunk analytic story (optional - enhances context)
|
|
15
|
+
- **KQL Categories** - Filter KQL queries by category (Defender For Endpoint, Azure AD, Threat Hunting, etc.)
|
|
12
16
|
- **Auto-Indexing** - Automatically indexes detections on startup from configured paths
|
|
17
|
+
- **Multi-Format Support** - YAML (Sigma, Splunk), TOML (Elastic), Markdown (KQL)
|
|
13
18
|
- **Logsource Filtering** - Filter Sigma rules by category, product, or service
|
|
14
19
|
- **Severity Filtering** - Filter by criticality level
|
|
15
20
|
|
|
@@ -46,7 +51,10 @@ Add to your MCP config (`~/.cursor/mcp.json` or `.cursor/mcp.json` in your proje
|
|
|
46
51
|
"args": ["-y", "security-detections-mcp"],
|
|
47
52
|
"env": {
|
|
48
53
|
"SIGMA_PATHS": "/path/to/sigma/rules,/path/to/sigma/rules-threat-hunting",
|
|
49
|
-
"SPLUNK_PATHS": "/path/to/security_content/detections"
|
|
54
|
+
"SPLUNK_PATHS": "/path/to/security_content/detections",
|
|
55
|
+
"ELASTIC_PATHS": "/path/to/detection-rules/rules",
|
|
56
|
+
"STORY_PATHS": "/path/to/security_content/stories",
|
|
57
|
+
"KQL_PATHS": "/path/to/Hunting-Queries-Detection-Rules"
|
|
50
58
|
}
|
|
51
59
|
}
|
|
52
60
|
}
|
|
@@ -65,7 +73,10 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
|
65
73
|
"args": ["-y", "security-detections-mcp"],
|
|
66
74
|
"env": {
|
|
67
75
|
"SIGMA_PATHS": "/Users/you/sigma/rules,/Users/you/sigma/rules-threat-hunting",
|
|
68
|
-
"SPLUNK_PATHS": "/Users/you/security_content/detections"
|
|
76
|
+
"SPLUNK_PATHS": "/Users/you/security_content/detections",
|
|
77
|
+
"ELASTIC_PATHS": "/Users/you/detection-rules/rules",
|
|
78
|
+
"STORY_PATHS": "/Users/you/security_content/stories",
|
|
79
|
+
"KQL_PATHS": "/Users/you/Hunting-Queries-Detection-Rules"
|
|
69
80
|
}
|
|
70
81
|
}
|
|
71
82
|
}
|
|
@@ -74,79 +85,260 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
|
74
85
|
|
|
75
86
|
### Environment Variables
|
|
76
87
|
|
|
77
|
-
| Variable | Description |
|
|
78
|
-
|
|
79
|
-
| `SIGMA_PATHS` | Comma-separated paths to Sigma rule directories |
|
|
80
|
-
| `SPLUNK_PATHS` | Comma-separated paths to Splunk ESCU detection directories |
|
|
88
|
+
| Variable | Description | Required |
|
|
89
|
+
|----------|-------------|----------|
|
|
90
|
+
| `SIGMA_PATHS` | Comma-separated paths to Sigma rule directories | At least one source required |
|
|
91
|
+
| `SPLUNK_PATHS` | Comma-separated paths to Splunk ESCU detection directories | At least one source required |
|
|
92
|
+
| `ELASTIC_PATHS` | Comma-separated paths to Elastic detection rule directories | At least one source required |
|
|
93
|
+
| `KQL_PATHS` | Comma-separated paths to KQL hunting query directories | At least one source required |
|
|
94
|
+
| `STORY_PATHS` | Comma-separated paths to Splunk analytic story directories | No (enhances context) |
|
|
81
95
|
|
|
82
96
|
## Getting Detection Content
|
|
83
97
|
|
|
84
|
-
###
|
|
98
|
+
### Quick Start: Download All Rules (Copy & Paste)
|
|
99
|
+
|
|
100
|
+
Create a `detections` folder and download all sources with sparse checkout (only downloads the rules, not full repos):
|
|
85
101
|
|
|
86
102
|
```bash
|
|
87
|
-
|
|
88
|
-
|
|
103
|
+
# Create detections directory
|
|
104
|
+
mkdir -p detections && cd detections
|
|
105
|
+
|
|
106
|
+
# Download Sigma rules (~3,000+ rules)
|
|
107
|
+
git clone --depth 1 --filter=blob:none --sparse https://github.com/SigmaHQ/sigma.git
|
|
108
|
+
cd sigma && git sparse-checkout set rules rules-threat-hunting && cd ..
|
|
109
|
+
|
|
110
|
+
# Download Splunk ESCU detections + stories (~2,000+ detections, ~330 stories)
|
|
111
|
+
git clone --depth 1 --filter=blob:none --sparse https://github.com/splunk/security_content.git
|
|
112
|
+
cd security_content && git sparse-checkout set detections stories && cd ..
|
|
113
|
+
|
|
114
|
+
# Download Elastic detection rules (~1,500+ rules)
|
|
115
|
+
git clone --depth 1 --filter=blob:none --sparse https://github.com/elastic/detection-rules.git
|
|
116
|
+
cd detection-rules && git sparse-checkout set rules && cd ..
|
|
117
|
+
|
|
118
|
+
# Download KQL hunting queries (~300+ queries)
|
|
119
|
+
git clone --depth 1 https://github.com/Bert-JanP/Hunting-Queries-Detection-Rules.git kql
|
|
120
|
+
|
|
121
|
+
echo "Done! Configure your MCP with these paths:"
|
|
122
|
+
echo " SIGMA_PATHS: $(pwd)/sigma/rules,$(pwd)/sigma/rules-threat-hunting"
|
|
123
|
+
echo " SPLUNK_PATHS: $(pwd)/security_content/detections"
|
|
124
|
+
echo " ELASTIC_PATHS: $(pwd)/detection-rules/rules"
|
|
125
|
+
echo " KQL_PATHS: $(pwd)/kql"
|
|
126
|
+
echo " STORY_PATHS: $(pwd)/security_content/stories"
|
|
89
127
|
```
|
|
90
128
|
|
|
91
|
-
###
|
|
129
|
+
### Alternative: Full Clone
|
|
130
|
+
|
|
131
|
+
If you prefer full git history:
|
|
92
132
|
|
|
93
133
|
```bash
|
|
134
|
+
# Sigma Rules
|
|
135
|
+
git clone https://github.com/SigmaHQ/sigma.git
|
|
136
|
+
# Use rules/ and rules-threat-hunting/ directories
|
|
137
|
+
|
|
138
|
+
# Splunk ESCU
|
|
94
139
|
git clone https://github.com/splunk/security_content.git
|
|
95
|
-
# Use detections/
|
|
140
|
+
# Use detections/ and stories/ directories
|
|
141
|
+
|
|
142
|
+
# Elastic Detection Rules
|
|
143
|
+
git clone https://github.com/elastic/detection-rules.git
|
|
144
|
+
# Use rules/ directory
|
|
145
|
+
|
|
146
|
+
# KQL Hunting Queries
|
|
147
|
+
git clone https://github.com/Bert-JanP/Hunting-Queries-Detection-Rules.git
|
|
148
|
+
# Use entire repo
|
|
96
149
|
```
|
|
97
150
|
|
|
98
151
|
## MCP Tools
|
|
99
152
|
|
|
153
|
+
### Core Detection Tools
|
|
154
|
+
|
|
100
155
|
| Tool | Description |
|
|
101
156
|
|------|-------------|
|
|
102
|
-
| `search(query, limit)` | Full-text search across all detection fields |
|
|
157
|
+
| `search(query, limit)` | Full-text search across all detection fields (names, descriptions, queries, CVEs, process names, etc.) |
|
|
103
158
|
| `get_by_id(id)` | Get a single detection by its ID |
|
|
104
159
|
| `list_all(limit, offset)` | Paginated list of all detections |
|
|
105
|
-
| `list_by_source(source_type)` | Filter by `sigma` or `
|
|
106
|
-
| `
|
|
107
|
-
| `list_by_logsource(category, product, service)` | Filter Sigma rules by logsource |
|
|
108
|
-
| `list_by_severity(level)` | Filter by severity (informational/low/medium/high/critical) |
|
|
160
|
+
| `list_by_source(source_type)` | Filter by `sigma`, `splunk_escu`, `elastic`, or `kql` |
|
|
161
|
+
| `get_raw_yaml(id)` | Get the original YAML/TOML/Markdown content |
|
|
109
162
|
| `get_stats()` | Get index statistics |
|
|
110
163
|
| `rebuild_index()` | Force re-index from configured paths |
|
|
111
|
-
| `get_raw_yaml(id)` | Get the original YAML content |
|
|
112
164
|
|
|
113
|
-
|
|
165
|
+
### MITRE ATT&CK Filters
|
|
166
|
+
|
|
167
|
+
| Tool | Description |
|
|
168
|
+
|------|-------------|
|
|
169
|
+
| `list_by_mitre(technique_id)` | Filter by MITRE ATT&CK technique ID (e.g., T1059.001) |
|
|
170
|
+
| `list_by_mitre_tactic(tactic)` | Filter by tactic (execution, persistence, credential-access, etc.) |
|
|
171
|
+
|
|
172
|
+
### Vulnerability & Process Filters
|
|
173
|
+
|
|
174
|
+
| Tool | Description |
|
|
175
|
+
|------|-------------|
|
|
176
|
+
| `list_by_cve(cve_id)` | Find detections for a specific CVE (e.g., CVE-2024-27198) |
|
|
177
|
+
| `list_by_process_name(process_name)` | Find detections referencing a process (e.g., powershell.exe, w3wp.exe) |
|
|
178
|
+
| `list_by_data_source(data_source)` | Filter by data source (e.g., Sysmon, Windows Security) |
|
|
179
|
+
|
|
180
|
+
### Classification Filters
|
|
181
|
+
|
|
182
|
+
| Tool | Description |
|
|
183
|
+
|------|-------------|
|
|
184
|
+
| `list_by_logsource(category, product, service)` | Filter Sigma rules by logsource |
|
|
185
|
+
| `list_by_severity(level)` | Filter by severity (informational/low/medium/high/critical) |
|
|
186
|
+
| `list_by_detection_type(type)` | Filter by type (TTP, Anomaly, Hunting, Correlation) |
|
|
187
|
+
| `list_by_analytic_story(story)` | Filter by Splunk analytic story |
|
|
188
|
+
|
|
189
|
+
### KQL-Specific Filters
|
|
190
|
+
|
|
191
|
+
| Tool | Description |
|
|
192
|
+
|------|-------------|
|
|
193
|
+
| `list_by_kql_category(category)` | Filter KQL by category (e.g., "Defender For Endpoint", "Azure Active Directory", "Threat Hunting") |
|
|
194
|
+
| `list_by_kql_tag(tag)` | Filter KQL by tag (e.g., "ransomware", "hunting", "ti-feed", "dfir") |
|
|
195
|
+
| `list_by_kql_datasource(data_source)` | Filter KQL by Microsoft data source (e.g., "DeviceProcessEvents", "SigninLogs") |
|
|
196
|
+
|
|
197
|
+
### Story Tools (Optional)
|
|
198
|
+
|
|
199
|
+
| Tool | Description |
|
|
200
|
+
|------|-------------|
|
|
201
|
+
| `search_stories(query, limit)` | Search analytic stories by narrative and description |
|
|
202
|
+
| `get_story(name)` | Get detailed story information |
|
|
203
|
+
| `list_stories(limit, offset)` | List all analytic stories |
|
|
204
|
+
| `list_stories_by_category(category)` | Filter stories by category (Malware, Adversary Tactics, etc.) |
|
|
205
|
+
|
|
206
|
+
### Efficient Analysis Tools (Token-Optimized)
|
|
207
|
+
|
|
208
|
+
These tools do heavy processing server-side and return minimal, actionable data:
|
|
209
|
+
|
|
210
|
+
| Tool | Description | Output Size |
|
|
211
|
+
|------|-------------|-------------|
|
|
212
|
+
| `analyze_coverage(source_type?)` | Get coverage stats by tactic, top techniques, weak spots | ~2KB |
|
|
213
|
+
| `identify_gaps(threat_profile, source_type?)` | Find gaps for ransomware, apt, persistence, etc. | ~500B |
|
|
214
|
+
| `suggest_detections(technique_id, source_type?)` | Get detection ideas for a technique | ~2KB |
|
|
215
|
+
| `get_technique_ids(source_type?, tactic?, severity?)` | Get only technique IDs (no full objects) | ~200B |
|
|
216
|
+
| `generate_navigator_layer(name, source_type?, tactic?)` | Generate ATT&CK Navigator layer JSON | ~3KB |
|
|
217
|
+
|
|
218
|
+
**Why use these?** Traditional tools return full detection objects (~50KB+ per query). These return only what you need, saving 25x+ tokens.
|
|
219
|
+
|
|
220
|
+
## Claude Code Skills
|
|
221
|
+
|
|
222
|
+
This repo includes [Claude Code Skills](https://code.claude.com/docs/en/skills) in `.claude/skills/` that teach Claude efficient workflows:
|
|
114
223
|
|
|
115
|
-
|
|
224
|
+
| Skill | Purpose |
|
|
225
|
+
|-------|---------|
|
|
226
|
+
| `coverage-analysis` | Efficient coverage analysis using the token-optimized tools |
|
|
116
227
|
|
|
117
|
-
|
|
228
|
+
**Why skills?** Instead of figuring out methodology each time (wasting tokens), skills teach Claude once.
|
|
118
229
|
|
|
119
|
-
|
|
230
|
+
You can also install personal skills to `~/.claude/skills/` for cross-project use.
|
|
120
231
|
|
|
121
|
-
|
|
232
|
+
### Example: Efficient Coverage Analysis
|
|
122
233
|
|
|
123
|
-
|
|
234
|
+
```
|
|
235
|
+
You: "What's my Elastic coverage against ransomware?"
|
|
236
|
+
|
|
237
|
+
AI uses skills + efficient tools:
|
|
238
|
+
1. analyze_coverage(source_type="elastic") → Stats by tactic
|
|
239
|
+
2. identify_gaps(threat_profile="ransomware") → Prioritized gaps
|
|
240
|
+
3. suggest_detections(technique_id="T1486") → Fix top gap
|
|
241
|
+
|
|
242
|
+
Total: ~5KB of data vs ~500KB with traditional tools
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Example Workflows
|
|
246
|
+
|
|
247
|
+
### Find PowerShell Detections
|
|
248
|
+
|
|
249
|
+
```
|
|
250
|
+
LLM: "Find me PowerShell detections related to base64 encoding"
|
|
251
|
+
Tool: search(query="powershell base64", limit=5)
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Check CVE Coverage
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
LLM: "Do we have detections for CVE-2024-27198?"
|
|
258
|
+
Tool: list_by_cve(cve_id="CVE-2024-27198")
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Compare Coverage Across Sources
|
|
262
|
+
|
|
263
|
+
```
|
|
264
|
+
LLM: "What detections do we have for credential dumping?"
|
|
265
|
+
Tool: search(query="credential dumping", limit=10)
|
|
266
|
+
→ Returns results from Sigma, Splunk, Elastic, AND KQL
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Find Web Server Attack Detections
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
LLM: "What detections cover IIS web server attacks?"
|
|
273
|
+
Tool: list_by_process_name(process_name="w3wp.exe")
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Explore a Threat Campaign
|
|
277
|
+
|
|
278
|
+
```
|
|
279
|
+
LLM: "Tell me about ransomware detections"
|
|
280
|
+
Tool: search_stories(query="ransomware")
|
|
281
|
+
Tool: list_by_analytic_story(story="Ransomware")
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Find KQL Hunting Queries for Defender
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
LLM: "What KQL queries do we have for Defender For Endpoint?"
|
|
288
|
+
Tool: list_by_kql_category(category="Defender For Endpoint")
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Search for BloodHound Detections
|
|
292
|
+
|
|
293
|
+
```
|
|
294
|
+
LLM: "Find detections for BloodHound usage"
|
|
295
|
+
Tool: search(query="bloodhound", limit=10)
|
|
296
|
+
→ Returns KQL hunting queries and other source detections
|
|
297
|
+
```
|
|
124
298
|
|
|
125
299
|
## Unified Schema
|
|
126
300
|
|
|
127
|
-
|
|
301
|
+
All detection sources (Sigma, Splunk, Elastic, KQL) are normalized to a common schema:
|
|
302
|
+
|
|
303
|
+
### Core Fields
|
|
128
304
|
|
|
129
305
|
| Field | Description |
|
|
130
306
|
|-------|-------------|
|
|
131
|
-
| `id` | Unique identifier
|
|
307
|
+
| `id` | Unique identifier |
|
|
132
308
|
| `name` | Detection name/title |
|
|
133
309
|
| `description` | What the detection looks for |
|
|
134
|
-
| `query` | Detection logic (Sigma YAML
|
|
135
|
-
| `source_type` | `sigma` or `
|
|
136
|
-
| `mitre_ids` | Mapped MITRE ATT&CK technique IDs |
|
|
137
|
-
| `logsource_category` | Sigma logsource category |
|
|
138
|
-
| `logsource_product` | Sigma logsource product (windows, linux, etc.) |
|
|
139
|
-
| `logsource_service` | Sigma logsource service |
|
|
310
|
+
| `query` | Detection logic (Sigma YAML, Splunk SPL, Elastic EQL, or KQL) |
|
|
311
|
+
| `source_type` | `sigma`, `splunk_escu`, `elastic`, or `kql` |
|
|
140
312
|
| `severity` | Detection severity level |
|
|
141
|
-
| `status` | Rule status (stable, test, experimental, etc.) |
|
|
313
|
+
| `status` | Rule status (stable, test, experimental, production, etc.) |
|
|
142
314
|
| `author` | Rule author |
|
|
143
|
-
| `date_created` | Creation date |
|
|
144
|
-
| `date_modified` | Last modification date |
|
|
145
|
-
| `references` | External references |
|
|
146
|
-
| `falsepositives` | Known false positive scenarios |
|
|
147
|
-
| `tags` | All tags (MITRE, analytic stories, etc.) |
|
|
148
315
|
| `file_path` | Original file path |
|
|
149
|
-
| `raw_yaml` | Original YAML content |
|
|
316
|
+
| `raw_yaml` | Original YAML/TOML/Markdown content |
|
|
317
|
+
|
|
318
|
+
### Enhanced Fields (for Semantic Search)
|
|
319
|
+
|
|
320
|
+
| Field | Description |
|
|
321
|
+
|-------|-------------|
|
|
322
|
+
| `mitre_ids` | Mapped MITRE ATT&CK technique IDs |
|
|
323
|
+
| `mitre_tactics` | Extracted MITRE tactics (execution, persistence, etc.) |
|
|
324
|
+
| `cves` | CVE identifiers (e.g., CVE-2024-27198) |
|
|
325
|
+
| `analytic_stories` | Splunk analytic story names |
|
|
326
|
+
| `process_names` | Process names referenced in detection |
|
|
327
|
+
| `file_paths` | Interesting file paths referenced |
|
|
328
|
+
| `registry_paths` | Registry paths referenced |
|
|
329
|
+
| `data_sources` | Required data sources (Sysmon, DeviceProcessEvents, etc.) |
|
|
330
|
+
| `detection_type` | TTP, Anomaly, Hunting, or Correlation |
|
|
331
|
+
| `asset_type` | Endpoint, Web Server, Cloud, Network |
|
|
332
|
+
| `security_domain` | endpoint, network, cloud, access |
|
|
333
|
+
|
|
334
|
+
### KQL-Specific Fields
|
|
335
|
+
|
|
336
|
+
| Field | Description |
|
|
337
|
+
|-------|-------------|
|
|
338
|
+
| `kql_category` | Category derived from folder path (e.g., "Defender For Endpoint") |
|
|
339
|
+
| `kql_tags` | Extracted tags (e.g., "ransomware", "hunting", "ti-feed") |
|
|
340
|
+
| `kql_keywords` | Security keywords extracted for search |
|
|
341
|
+
| `platforms` | Platforms (windows, azure-ad, office-365, etc.) |
|
|
150
342
|
|
|
151
343
|
## Database
|
|
152
344
|
|
|
@@ -158,17 +350,42 @@ The index is stored at `~/.cache/security-detections-mcp/detections.sqlite`.
|
|
|
158
350
|
|
|
159
351
|
## Supported Detection Formats
|
|
160
352
|
|
|
161
|
-
### Sigma Rules
|
|
353
|
+
### Sigma Rules (YAML)
|
|
162
354
|
|
|
163
355
|
Based on the [official Sigma specification](https://github.com/SigmaHQ/sigma-specification):
|
|
164
356
|
- All required fields: `title`, `logsource`, `detection`
|
|
165
357
|
- All optional fields: `id`, `status`, `description`, `author`, `date`, `modified`, `references`, `tags`, `level`, `falsepositives`, etc.
|
|
358
|
+
- CVE tags extracted from `tags` field (e.g., `cve.2021-1675`)
|
|
166
359
|
|
|
167
|
-
### Splunk ESCU
|
|
360
|
+
### Splunk ESCU (YAML)
|
|
168
361
|
|
|
169
362
|
From [Splunk Security Content](https://github.com/splunk/security_content):
|
|
170
363
|
- Required: `name`, `id`, `search`
|
|
171
|
-
- Optional: `description`, `author`, `date`, `status`, `references`, `tags` (including `mitre_attack_id`, `analytic_story`)
|
|
364
|
+
- Optional: `description`, `author`, `date`, `status`, `references`, `tags` (including `mitre_attack_id`, `analytic_story`, `cve`)
|
|
365
|
+
|
|
366
|
+
### Splunk Analytic Stories (YAML - Optional)
|
|
367
|
+
|
|
368
|
+
From [Splunk Security Content stories](https://github.com/splunk/security_content/tree/develop/stories):
|
|
369
|
+
- Provides rich narrative context for threat campaigns
|
|
370
|
+
- Enhances semantic search with detailed descriptions
|
|
371
|
+
- Links detections to broader threat context
|
|
372
|
+
|
|
373
|
+
### Elastic Detection Rules (TOML)
|
|
374
|
+
|
|
375
|
+
From [Elastic Detection Rules](https://github.com/elastic/detection-rules):
|
|
376
|
+
- Required: `rule.name`, `rule.rule_id`
|
|
377
|
+
- Optional: `rule.description`, `rule.query`, `rule.severity`, `rule.tags`, `rule.threat` (MITRE mappings)
|
|
378
|
+
- Supports EQL, KQL, Lucene, and ESQL query languages
|
|
379
|
+
|
|
380
|
+
### KQL Hunting Queries (Markdown)
|
|
381
|
+
|
|
382
|
+
From [Bert-JanP/Hunting-Queries-Detection-Rules](https://github.com/Bert-JanP/Hunting-Queries-Detection-Rules):
|
|
383
|
+
- Microsoft Defender XDR and Azure Sentinel hunting queries
|
|
384
|
+
- Extracts title from markdown heading
|
|
385
|
+
- Extracts KQL from fenced code blocks
|
|
386
|
+
- Extracts MITRE technique IDs from tables
|
|
387
|
+
- Derives category from folder path
|
|
388
|
+
- Extracts data sources (DeviceProcessEvents, SigninLogs, etc.)
|
|
172
389
|
|
|
173
390
|
## Development
|
|
174
391
|
|
|
@@ -180,7 +397,87 @@ npm install
|
|
|
180
397
|
npm run build
|
|
181
398
|
|
|
182
399
|
# Run with paths
|
|
183
|
-
SIGMA_PATHS="./detections/sigma/rules"
|
|
400
|
+
SIGMA_PATHS="./detections/sigma/rules" \
|
|
401
|
+
SPLUNK_PATHS="./detections/splunk/detections" \
|
|
402
|
+
ELASTIC_PATHS="./detections/elastic/rules" \
|
|
403
|
+
KQL_PATHS="./detections/kql" \
|
|
404
|
+
STORY_PATHS="./detections/splunk/stories" \
|
|
405
|
+
npm start
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
## Stats (with full content)
|
|
409
|
+
|
|
410
|
+
When fully indexed with all sources:
|
|
411
|
+
|
|
412
|
+
| Source | Count |
|
|
413
|
+
|--------|-------|
|
|
414
|
+
| Sigma Rules | ~3,000+ |
|
|
415
|
+
| Splunk ESCU | ~2,000+ |
|
|
416
|
+
| Elastic Rules | ~1,500+ |
|
|
417
|
+
| KQL Queries | ~300+ |
|
|
418
|
+
| Analytic Stories | ~330 |
|
|
419
|
+
| **Total** | **~7,000+** |
|
|
420
|
+
|
|
421
|
+
## 🔗 Using with MITRE ATT&CK MCP
|
|
422
|
+
|
|
423
|
+
**This MCP pairs perfectly with [mitre-attack-mcp](https://github.com/MHaggis/mitre-attack-mcp)** for complete threat coverage analysis:
|
|
424
|
+
|
|
425
|
+
| MCP | Purpose |
|
|
426
|
+
|-----|---------|
|
|
427
|
+
| **security-detections-mcp** | Query 7,000+ detection rules (Sigma, Splunk ESCU, Elastic, KQL) |
|
|
428
|
+
| **mitre-attack-mcp** | Analyze coverage against ATT&CK framework, generate Navigator layers |
|
|
429
|
+
|
|
430
|
+
### Combined Workflow (Efficient)
|
|
431
|
+
|
|
432
|
+
```
|
|
433
|
+
You: "What's my coverage against APT29?"
|
|
434
|
+
|
|
435
|
+
LLM workflow (3 calls, ~10KB total):
|
|
436
|
+
1. mitre-attack-mcp → get_group_techniques("G0016") # APT29's TTPs
|
|
437
|
+
2. detections-mcp → analyze_coverage(source_type="elastic") # Your coverage
|
|
438
|
+
3. mitre-attack-mcp → find_group_gaps("G0016", your_coverage) # The gaps
|
|
439
|
+
|
|
440
|
+
Result: Prioritized gap list, not 500KB of raw data
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### Generate Navigator Layer (1 call)
|
|
444
|
+
|
|
445
|
+
```
|
|
446
|
+
You: "Generate a Navigator layer for my initial access coverage"
|
|
447
|
+
|
|
448
|
+
LLM: generate_navigator_layer(
|
|
449
|
+
name="Initial Access Coverage",
|
|
450
|
+
source_type="elastic",
|
|
451
|
+
tactic="initial-access"
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
→ Returns ready-to-import Navigator JSON
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### Install Both Together
|
|
458
|
+
|
|
459
|
+
```json
|
|
460
|
+
{
|
|
461
|
+
"mcpServers": {
|
|
462
|
+
"security-detections": {
|
|
463
|
+
"command": "npx",
|
|
464
|
+
"args": ["-y", "security-detections-mcp"],
|
|
465
|
+
"env": {
|
|
466
|
+
"SIGMA_PATHS": "/path/to/sigma/rules",
|
|
467
|
+
"SPLUNK_PATHS": "/path/to/security_content/detections",
|
|
468
|
+
"ELASTIC_PATHS": "/path/to/detection-rules/rules",
|
|
469
|
+
"KQL_PATHS": "/path/to/kql-hunting-queries"
|
|
470
|
+
}
|
|
471
|
+
},
|
|
472
|
+
"mitre-attack": {
|
|
473
|
+
"command": "npx",
|
|
474
|
+
"args": ["-y", "mitre-attack-mcp"],
|
|
475
|
+
"env": {
|
|
476
|
+
"ATTACK_DOMAIN": "enterprise-attack"
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
184
481
|
```
|
|
185
482
|
|
|
186
483
|
## License
|
package/dist/db.d.ts
CHANGED
|
@@ -1,17 +1,91 @@
|
|
|
1
1
|
import Database from 'better-sqlite3';
|
|
2
|
-
import type { Detection, IndexStats } from './types.js';
|
|
2
|
+
import type { Detection, IndexStats, AnalyticStory } from './types.js';
|
|
3
3
|
export declare function getDbPath(): string;
|
|
4
4
|
export declare function initDb(): Database.Database;
|
|
5
5
|
export declare function clearDb(): void;
|
|
6
|
+
export declare function recreateDb(): void;
|
|
6
7
|
export declare function insertDetection(detection: Detection): void;
|
|
7
8
|
export declare function searchDetections(query: string, limit?: number): Detection[];
|
|
8
9
|
export declare function getDetectionById(id: string): Detection | null;
|
|
9
10
|
export declare function listDetections(limit?: number, offset?: number): Detection[];
|
|
10
|
-
export declare function listBySource(sourceType: 'sigma' | 'splunk_escu', limit?: number, offset?: number): Detection[];
|
|
11
|
+
export declare function listBySource(sourceType: 'sigma' | 'splunk_escu' | 'elastic' | 'kql', limit?: number, offset?: number): Detection[];
|
|
11
12
|
export declare function listByMitre(techniqueId: string, limit?: number, offset?: number): Detection[];
|
|
12
13
|
export declare function listByLogsource(category?: string, product?: string, service?: string, limit?: number, offset?: number): Detection[];
|
|
13
14
|
export declare function listBySeverity(level: string, limit?: number, offset?: number): Detection[];
|
|
15
|
+
export declare function listByCve(cveId: string, limit?: number, offset?: number): Detection[];
|
|
16
|
+
export declare function listByAnalyticStory(story: string, limit?: number, offset?: number): Detection[];
|
|
17
|
+
export declare function listByProcessName(processName: string, limit?: number, offset?: number): Detection[];
|
|
18
|
+
export declare function listByDetectionType(detectionType: string, limit?: number, offset?: number): Detection[];
|
|
19
|
+
export declare function listByDataSource(dataSource: string, limit?: number, offset?: number): Detection[];
|
|
20
|
+
export declare function listByKqlCategory(category: string, limit?: number, offset?: number): Detection[];
|
|
21
|
+
export declare function listByKqlTag(tag: string, limit?: number, offset?: number): Detection[];
|
|
22
|
+
export declare function listByKqlDatasource(dataSource: string, limit?: number, offset?: number): Detection[];
|
|
23
|
+
export declare function listByMitreTactic(tactic: string, limit?: number, offset?: number): Detection[];
|
|
14
24
|
export declare function getStats(): IndexStats;
|
|
15
25
|
export declare function getRawYaml(id: string): string | null;
|
|
16
26
|
export declare function dbExists(): boolean;
|
|
17
27
|
export declare function getDetectionCount(): number;
|
|
28
|
+
export declare function insertStory(story: AnalyticStory): void;
|
|
29
|
+
export declare function getStoryByName(name: string): AnalyticStory | null;
|
|
30
|
+
export declare function getStoryById(id: string): AnalyticStory | null;
|
|
31
|
+
export declare function searchStories(query: string, limit?: number): AnalyticStory[];
|
|
32
|
+
export declare function listStories(limit?: number, offset?: number): AnalyticStory[];
|
|
33
|
+
export declare function listStoriesByCategory(category: string, limit?: number, offset?: number): AnalyticStory[];
|
|
34
|
+
export declare function getStoryCount(): number;
|
|
35
|
+
export interface TechniqueIdFilters {
|
|
36
|
+
source_type?: 'sigma' | 'splunk_escu' | 'elastic';
|
|
37
|
+
tactic?: string;
|
|
38
|
+
severity?: string;
|
|
39
|
+
}
|
|
40
|
+
export declare function getTechniqueIds(filters?: TechniqueIdFilters): string[];
|
|
41
|
+
export interface CoverageReport {
|
|
42
|
+
summary: {
|
|
43
|
+
total_techniques: number;
|
|
44
|
+
total_detections: number;
|
|
45
|
+
coverage_by_tactic: Record<string, {
|
|
46
|
+
covered: number;
|
|
47
|
+
total: number;
|
|
48
|
+
percent: number;
|
|
49
|
+
}>;
|
|
50
|
+
};
|
|
51
|
+
top_covered: Array<{
|
|
52
|
+
technique: string;
|
|
53
|
+
detection_count: number;
|
|
54
|
+
}>;
|
|
55
|
+
weak_coverage: Array<{
|
|
56
|
+
technique: string;
|
|
57
|
+
detection_count: number;
|
|
58
|
+
}>;
|
|
59
|
+
}
|
|
60
|
+
export declare function analyzeCoverage(sourceType?: 'sigma' | 'splunk_escu' | 'elastic'): CoverageReport;
|
|
61
|
+
export interface GapAnalysis {
|
|
62
|
+
threat_profile: string;
|
|
63
|
+
total_gaps: number;
|
|
64
|
+
critical_gaps: Array<{
|
|
65
|
+
technique: string;
|
|
66
|
+
priority: string;
|
|
67
|
+
reason: string;
|
|
68
|
+
}>;
|
|
69
|
+
covered: string[];
|
|
70
|
+
recommendations: string[];
|
|
71
|
+
}
|
|
72
|
+
export declare function identifyGaps(threatProfile: string, sourceType?: 'sigma' | 'splunk_escu' | 'elastic'): GapAnalysis;
|
|
73
|
+
export interface DetectionSuggestion {
|
|
74
|
+
technique_id: string;
|
|
75
|
+
existing_detections: Array<{
|
|
76
|
+
id: string;
|
|
77
|
+
name: string;
|
|
78
|
+
source: string;
|
|
79
|
+
}>;
|
|
80
|
+
data_sources_needed: string[];
|
|
81
|
+
detection_ideas: string[];
|
|
82
|
+
}
|
|
83
|
+
export declare function suggestDetections(techniqueId: string, sourceType?: 'sigma' | 'splunk_escu' | 'elastic'): DetectionSuggestion;
|
|
84
|
+
export interface NavigatorLayerOptions {
|
|
85
|
+
name: string;
|
|
86
|
+
description?: string;
|
|
87
|
+
source_type?: 'sigma' | 'splunk_escu' | 'elastic';
|
|
88
|
+
tactic?: string;
|
|
89
|
+
severity?: string;
|
|
90
|
+
}
|
|
91
|
+
export declare function generateNavigatorLayer(options: NavigatorLayerOptions): object;
|