Automating IOC Enrichment
When to Use
Use this skill when:
- Building a SOAR playbook that automatically enriches SIEM alerts with threat intelligence context before routing to analysts
- Creating a Python pipeline for bulk IOC enrichment from phishing email submissions
- Reducing analyst mean time to triage (MTTT) by pre-populating alert context with VT, Shodan, and MISP data
Do not use this skill for fully automated blocking decisions without human review — enrichment automation should inform decisions, not execute blocks autonomously for high-impact actions.
Prerequisites
- SOAR platform (Cortex XSOAR, Splunk SOAR, Tines, or n8n) or Python 3.9+ environment
- API keys: VirusTotal, AbuseIPDB, Shodan, and at minimum one TIP (MISP or OpenCTI)
- SIEM integration endpoint for alert consumption
- Rate limit budgets documented per API (VT: 4/min free, 500/min enterprise)
Workflow
Step 1: Design Enrichment Pipeline Architecture
Define the enrichment flow for each IOC type:
SIEM Alert → Extract IOCs → Classify Type → Route to enrichment functions
IP Address → AbuseIPDB + Shodan + VirusTotal IP + MISP
Domain → VirusTotal Domain + PassiveTotal + Shodan + MISP
URL → URLScan.io + VirusTotal URL + Google Safe Browse
File Hash → VirusTotal Files + MalwareBazaar + MISP
→ Aggregate results → Calculate confidence score → Update alert → Notify analyst
Step 2: Implement Python Enrichment Functions
import requests
import time
from dataclasses import dataclass, field
from typing import Optional
RATE_LIMIT_DELAY = 0.25 # 4 requests/second for VT free tier
@dataclass
class EnrichmentResult:
ioc_value: str
ioc_type: str
vt_malicious: int = 0
vt_total: int = 0
abuse_confidence: int = 0
shodan_ports: list = field(default_factory=list)
misp_events: list = field(default_factory=list)
confidence_score: int = 0
def enrich_ip(ip: str, vt_key: str, abuse_key: str, shodan_key: str) -> EnrichmentResult:
result = EnrichmentResult(ip, "ip")
# VirusTotal IP lookup
vt_resp = requests.get(
f"https://www.virustotal.com/api/v3/ip_addresses/{ip}",
headers={"x-apikey": vt_key}
)
if vt_resp.status_code == 200:
stats = vt_resp.json()["data"]["attributes"]["last_analysis_stats"]
result.vt_malicious = stats.get("malicious", 0)
result.vt_total = sum(stats.values())
time.sleep(RATE_LIMIT_DELAY)
# AbuseIPDB
abuse_resp = requests.get(
"https://api.abuseipdb.com/api/v2/check",
headers={"Key": abuse_key, "Accept": "application/json"},
params={"ipAddress": ip, "maxAgeInDays": 90}
)
if abuse_resp.status_code == 200:
result.abuse_confidence = abuse_resp.json()["data"]["abuseConfidenceScore"]
# Calculate composite confidence score
result.confidence_score = min(
(result.vt_malicious / max(result.vt_total, 1)) * 60 +
(result.abuse_confidence / 100) * 40, 100
)
return result
def enrich_hash(sha256: str, vt_key: str) -> EnrichmentResult:
result = EnrichmentResult(sha256, "sha256")
vt_resp = requests.get(
f"https://www.virustotal.com/api/v3/files/{sha256}",
headers={"x-apikey": vt_key}
)
if vt_resp.status_code == 200:
stats = vt_resp.json()["data"]["attributes"]["last_analysis_stats"]
result.vt_malicious = stats.get("malicious", 0)
result.vt_total = sum(stats.values())
result.confidence_score = int((result.vt_malicious / max(result.vt_total, 1)) * 100)
return result
Step 3: Build SOAR Playbook (Cortex XSOAR)
In Cortex XSOAR, create an enrichment playbook:
- Trigger: Alert created in SIEM (via webhook or polling)
- Extract IOCs: Use "Extract Indicators" task with regex patterns for IP, domain, URL, hash
- Parallel enrichment: Fan-out to multiple enrichment tasks simultaneously
- VT Enrichment: Call
!vt-file-scan or !vt-ip-scan commands
- AbuseIPDB check: Call
!abuseipdb-check-ip command
- MISP Lookup: Call
!misp-search for cross-referencing
- Score aggregation: Python transform task computing composite score
- Conditional routing: If score ≥70 → High Priority queue; if 40–69 → Medium; <40 → Auto-close with note
- Alert enrichment: Write enrichment results to alert context for analyst view
Step 4: Handle Rate Limiting and Failures
import time
from functools import wraps
def rate_limited(max_per_second):
min_interval = 1.0 / max_per_second
def decorator(func):
last_called = [0.0]
@wraps(func)
def wrapper(*args, **kwargs):
elapsed = time.time() - last_called[0]
wait = min_interval - elapsed
if wait > 0:
time.sleep(wait)
result = func(*args, **kwargs)
last_called[0] = time.time()
return result
return wrapper
return decorator
def retry_on_429(max_retries=3):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(max_retries):
response = func(*args, **kwargs)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 60))
time.sleep(retry_after)
else:
return response
return wrapper
return decorator
Step 5: Metrics and Tuning
Track pipeline performance weekly:
- Enrichment latency: Target <30 seconds from alert trigger to enriched output
- API success rate: Target >99% (identify rate limit or outage events)
- True positive rate: Track analyst overrides of automated confidence scores
- Cost: Track API call volume against budget (VT Enterprise: $X per 1M lookups)
Key Concepts
| Term |
Definition |
| SOAR |
Security Orchestration, Automation, and Response — platform for automating security workflows and integrating disparate tools |
| Enrichment Playbook |
Automated workflow sequence that adds contextual intelligence to raw security events |
| Rate Limiting |
API provider restrictions on request frequency (e.g., VT free: 4 requests/minute); pipelines must respect these limits |
| Composite Confidence Score |
Single score aggregating signals from multiple enrichment sources using weighted formula |
| Fan-out Pattern |
Parallel execution of multiple enrichment queries simultaneously to minimize total enrichment latency |
Tools & Systems
- Cortex XSOAR (Palo Alto): Enterprise SOAR with 700+ marketplace integrations including VT, MISP, Shodan, and AbuseIPDB
- Splunk SOAR (Phantom): SOAR platform with Python-based playbooks; native Splunk SIEM integration
- Tines: No-code SOAR platform with webhook-driven automation; cost-effective for smaller teams
- TheHive + Cortex: Open-source IR/enrichment platform with observable enrichment via Cortex analyzers
Common Pitfalls
- Blocking on enrichment latency: If enrichment takes >5 minutes, analysts start working unenriched alerts, defeating the purpose. Set timeout limits and provide partial results.
- No caching: Querying the same IOC 50 times generates unnecessary API costs. Cache enrichment results for 24 hours by default.
- Ignoring API failures silently: Failed enrichment calls should be logged and trigger fallback logic, not silently produce empty results that appear as clean IOCs.
- Automating blocks on enrichment score alone: Composite scores contain false positives; require human confirmation for blocking decisions against shared infrastructure.
1---2name: automating-ioc-enrichment3description: Automates the enrichment of raw indicators of compromise with multi-source threat intelligence context using SOAR platforms, Python pipelines, or TIP playbooks to reduce analyst triage time and standardize enrichment outputs. Use when building automated enrichment workflows integrated with SIEM alerts, email submission pipelines, or bulk IOC processing from threat feeds. Activates for requests involving SOAR enrichment, Cortex XSOAR, Splunk SOAR, TheHive, Python enrichment pipelines, or automated IOC processing.4license: Apache-2.05---6# Automating IOC Enrichment
7
8## When to Use
9
10Use this skill when:
11- Building a SOAR playbook that automatically enriches SIEM alerts with threat intelligence context before routing to analysts
12- Creating a Python pipeline for bulk IOC enrichment from phishing email submissions
13- Reducing analyst mean time to triage (MTTT) by pre-populating alert context with VT, Shodan, and MISP data
14
15**Do not use** this skill for fully automated blocking decisions without human review — enrichment automation should inform decisions, not execute blocks autonomously for high-impact actions.
16
17## Prerequisites
18
19- SOAR platform (Cortex XSOAR, Splunk SOAR, Tines, or n8n) or Python 3.9+ environment
20- API keys: VirusTotal, AbuseIPDB, Shodan, and at minimum one TIP (MISP or OpenCTI)
21- SIEM integration endpoint for alert consumption
22- Rate limit budgets documented per API (VT: 4/min free, 500/min enterprise)
23
24## Workflow
25
26### Step 1: Design Enrichment Pipeline Architecture
27
28Define the enrichment flow for each IOC type:
29```
30SIEM Alert → Extract IOCs → Classify Type → Route to enrichment functions
31 IP Address → AbuseIPDB + Shodan + VirusTotal IP + MISP
32 Domain → VirusTotal Domain + PassiveTotal + Shodan + MISP
33 URL → URLScan.io + VirusTotal URL + Google Safe Browse
34 File Hash → VirusTotal Files + MalwareBazaar + MISP
35→ Aggregate results → Calculate confidence score → Update alert → Notify analyst
36```
37
38### Step 2: Implement Python Enrichment Functions
39
40```python
41import requests
42import time
43from dataclasses import dataclass, field
44from typing import Optional
45
46RATE_LIMIT_DELAY = 0.25 # 4 requests/second for VT free tier
47
48@dataclass
49class EnrichmentResult:
50 ioc_value: str
51 ioc_type: str
52 vt_malicious: int = 0
53 vt_total: int = 0
54 abuse_confidence: int = 0
55 shodan_ports: list = field(default_factory=list)
56 misp_events: list = field(default_factory=list)
57 confidence_score: int = 0
58
59def enrich_ip(ip: str, vt_key: str, abuse_key: str, shodan_key: str) -> EnrichmentResult:
60 result = EnrichmentResult(ip, "ip")
61
62 # VirusTotal IP lookup
63 vt_resp = requests.get(
64 f"https://www.virustotal.com/api/v3/ip_addresses/{ip}",
65 headers={"x-apikey": vt_key}
66 )
67 if vt_resp.status_code == 200:
68 stats = vt_resp.json()["data"]["attributes"]["last_analysis_stats"]
69 result.vt_malicious = stats.get("malicious", 0)
70 result.vt_total = sum(stats.values())
71
72 time.sleep(RATE_LIMIT_DELAY)
73
74 # AbuseIPDB
75 abuse_resp = requests.get(
76 "https://api.abuseipdb.com/api/v2/check",
77 headers={"Key": abuse_key, "Accept": "application/json"},
78 params={"ipAddress": ip, "maxAgeInDays": 90}
79 )
80 if abuse_resp.status_code == 200:
81 result.abuse_confidence = abuse_resp.json()["data"]["abuseConfidenceScore"]
82
83 # Calculate composite confidence score
84 result.confidence_score = min(
85 (result.vt_malicious / max(result.vt_total, 1)) * 60 +
86 (result.abuse_confidence / 100) * 40, 100
87 )
88
89 return result
90
91def enrich_hash(sha256: str, vt_key: str) -> EnrichmentResult:
92 result = EnrichmentResult(sha256, "sha256")
93 vt_resp = requests.get(
94 f"https://www.virustotal.com/api/v3/files/{sha256}",
95 headers={"x-apikey": vt_key}
96 )
97 if vt_resp.status_code == 200:
98 stats = vt_resp.json()["data"]["attributes"]["last_analysis_stats"]
99 result.vt_malicious = stats.get("malicious", 0)
100 result.vt_total = sum(stats.values())
101 result.confidence_score = int((result.vt_malicious / max(result.vt_total, 1)) * 100)
102 return result
103```
104
105### Step 3: Build SOAR Playbook (Cortex XSOAR)
106
107In Cortex XSOAR, create an enrichment playbook:
1081. **Trigger**: Alert created in SIEM (via webhook or polling)
1092. **Extract IOCs**: Use "Extract Indicators" task with regex patterns for IP, domain, URL, hash
1103. **Parallel enrichment**: Fan-out to multiple enrichment tasks simultaneously
1114. **VT Enrichment**: Call `!vt-file-scan` or `!vt-ip-scan` commands
1125. **AbuseIPDB check**: Call `!abuseipdb-check-ip` command
1136. **MISP Lookup**: Call `!misp-search` for cross-referencing
1147. **Score aggregation**: Python transform task computing composite score
1158. **Conditional routing**: If score ≥70 → High Priority queue; if 40–69 → Medium; <40 → Auto-close with note
1169. **Alert enrichment**: Write enrichment results to alert context for analyst view
117
118### Step 4: Handle Rate Limiting and Failures
119
120```python
121import time
122from functools import wraps
123
124def rate_limited(max_per_second):
125 min_interval = 1.0 / max_per_second
126 def decorator(func):
127 last_called = [0.0]
128 @wraps(func)
129 def wrapper(*args, **kwargs):
130 elapsed = time.time() - last_called[0]
131 wait = min_interval - elapsed
132 if wait > 0:
133 time.sleep(wait)
134 result = func(*args, **kwargs)
135 last_called[0] = time.time()
136 return result
137 return wrapper
138 return decorator
139
140def retry_on_429(max_retries=3):
141 def decorator(func):
142 @wraps(func)
143 def wrapper(*args, **kwargs):
144 for attempt in range(max_retries):
145 response = func(*args, **kwargs)
146 if response.status_code == 429:
147 retry_after = int(response.headers.get("Retry-After", 60))
148 time.sleep(retry_after)
149 else:
150 return response
151 return wrapper
152 return decorator
153```
154
155### Step 5: Metrics and Tuning
156
157Track pipeline performance weekly:
158- **Enrichment latency**: Target <30 seconds from alert trigger to enriched output
159- **API success rate**: Target >99% (identify rate limit or outage events)
160- **True positive rate**: Track analyst overrides of automated confidence scores
161- **Cost**: Track API call volume against budget (VT Enterprise: $X per 1M lookups)
162
163## Key Concepts
164
165| Term | Definition |
166|------|-----------|
167| **SOAR** | Security Orchestration, Automation, and Response — platform for automating security workflows and integrating disparate tools |
168| **Enrichment Playbook** | Automated workflow sequence that adds contextual intelligence to raw security events |
169| **Rate Limiting** | API provider restrictions on request frequency (e.g., VT free: 4 requests/minute); pipelines must respect these limits |
170| **Composite Confidence Score** | Single score aggregating signals from multiple enrichment sources using weighted formula |
171| **Fan-out Pattern** | Parallel execution of multiple enrichment queries simultaneously to minimize total enrichment latency |
172
173## Tools & Systems
174
175- **Cortex XSOAR (Palo Alto)**: Enterprise SOAR with 700+ marketplace integrations including VT, MISP, Shodan, and AbuseIPDB
176- **Splunk SOAR (Phantom)**: SOAR platform with Python-based playbooks; native Splunk SIEM integration
177- **Tines**: No-code SOAR platform with webhook-driven automation; cost-effective for smaller teams
178- **TheHive + Cortex**: Open-source IR/enrichment platform with observable enrichment via Cortex analyzers
179
180## Common Pitfalls
181
182- **Blocking on enrichment latency**: If enrichment takes >5 minutes, analysts start working unenriched alerts, defeating the purpose. Set timeout limits and provide partial results.
183- **No caching**: Querying the same IOC 50 times generates unnecessary API costs. Cache enrichment results for 24 hours by default.
184- **Ignoring API failures silently**: Failed enrichment calls should be logged and trigger fallback logic, not silently produce empty results that appear as clean IOCs.
185- **Automating blocks on enrichment score alone**: Composite scores contain false positives; require human confirmation for blocking decisions against shared infrastructure.