Built a fully automated SOC pipeline from scratch. A security event fires on a Windows endpoint, Wazuh picks it up, Shuffle enriches and orchestrates the response, TheHive creates a case, analyst gets notified. Zero manual steps. Under 3 minutes end to end.
Most SOC training teaches you to use tools. I wanted to understand how they actually talk to each other and how to make them respond without waiting for a human in the loop. The goal wasn't to follow a guide, it was to build something that breaks, force myself to fix it, and document what I learned.
The cloud infrastructure has since been taken down to manage costs. Everything is documented here so it can be rebuilt.
| Component | Role | Hosted On |
|---|---|---|
| Wazuh 4.7.3 | SIEM and EDR - monitors the endpoint, matches rules, generates alerts | Ubuntu 22.04 Droplet (4GB / 2 vCPU) |
| Shuffle SOAR | Automation layer - connects all tools, runs the enrichment workflow | shuffler.io cloud |
| TheHive 5.2.4 | Case management - every alert becomes a tracked incident | Ubuntu 22.04 Droplet |
| AbuseIPDB | Threat intel - checks source IPs against a reputation database | API (external) |
| Sysmon | Windows telemetry - enriched process, network, and file events | Windows 10 endpoint |
1. Wazuh detects suspicious activity on the Windows 10 endpoint
│
▼
2. Alert forwarded to Shuffle via webhook
│
▼
3. Shuffle checks if source IP is external
└── if yes → queries AbuseIPDB for reputation score
│
▼
4. TheHive case created with full enriched alert context
│
▼
5. Email notification fires to analyst
Total time: under 3 minutes. Manual steps: zero.
TheHive v4 vs v5 API mismatch
The Shuffle app for TheHive was built for v4. TheHive 5.2.4 changed the endpoint from
/api/alert to /api/v1/alert and added two required fields (type and source) that v4 didn't enforce. Cases were being sent but silently not creating, no error, just nothing in TheHive.
Fixed by switching the Shuffle HTTP action to the correct endpoint and hardcoding the two missing fields as static values.
Shuffle webhook not receiving Wazuh alerts
Wazuh's
ossec.conf integration block needs the webhook URL and auth header in a specific format. Alerts were firing from Wazuh but Shuffle wasn't receiving them.
Fixed by correcting the <hook_url> and <api_key> tags in the integration config and validating through Shuffle's execution logs in real time.
AbuseIPDB rate limits burning through during testing
Free tier allows 1,000 lookups per day. Repeated simulated alerts were eating through that fast.
Fixed by adding a condition in Shuffle to only query AbuseIPDB when the source IP is a public address, skipping RFC1918 private ranges entirely. Reduced unnecessary API calls by about 70%.
{
"alert_id": "1714023901.12345",
"rule": {
"id": "100002",
"description": "Mimikatz credential dumping detected",
"level": 12
},
"agent": {
"name": "WIN10-LAB",
"ip": "192.168.10.50"
},
"data": {
"srcip": "203.0.113.42",
"abuse_confidence_score": 87,
"country": "CN",
"isp": "[redacted]"
},
"thehive_case_id": "~1234567",
"response_time_seconds": 142
}The Python and Bash automation scripts are in the /scripts folder.
| File | What It Does |
|---|---|
wazuh_thehive_integration.py |
Parses a Wazuh alert JSON and creates a TheHive 5 case via API |
ip_enrichment.py |
Queries AbuseIPDB for a given IP, skips private RFC1918 addresses |
alert_pipeline.sh |
End-to-end pipeline script — enrichment + TheHive case in one run |
- Add MITRE ATT&CK tags to every TheHive case automatically by mapping Wazuh rule IDs at the Shuffle layer
- Switch from email to Slack for notifications, faster response loop
- Containerize the whole stack with Docker Compose so it spins up in one command
- Add a feedback loop where false positive case closures in TheHive automatically tune the Wazuh rule threshold
Active Directory Home Lab the endpoint feeding events into this pipeline
