This stack integrates Wazuh (for threat detection and SIEM), Shuffle (for automation and orchestration), and DFIR-IRIS (for case management and investigation), with Discord/Gmail providing real-time notifications. Together, it enables automated alerting, enrichment, incident tracking, and collaborative response to security events.
- Wazuh: Security Information & Event Management (SIEM) and XDR solution for threat detection.
- Shuffle: Open-Source Security Orchestration, Automation, and Response (SOAR) platform for automating workflows
- DFIR-IRIS:Open-source Digital Forensics and Incident Response (DFIR) case management platform for alert triage, evidence handling, investigation tracking, and team collaboration
- Discord/Gmail: For real-time monitoring and notifications.
- Create a new Webhook Trigger in Shuffle.
- Set the webhook name to:
Wazuh Alerts - Copy the endpoint URL of the webhook.
Add the webhook configuration to Wazuh:
<integration>
<name>custom-webhook</name>
<hook_url>http://<your-shuffle-ip>:3001/api/v1/webhook/<webhook-id></hook_url>
<level>1</level>
<alert_format>json</alert_format>
</integration>Start the webhook in Shuffle, then restart the Wazuh manager:
sudo systemctl restart wazuh-managerLogs from Wazuh are now sent to Shuffle via the webhook.
- Add a Repeat Back to Me app in the workflow.
- Set the name to:
Repeat Alert
We are only concerned with alerts where level > 7.
- If alert level < 7:
Send a formatted message to Discord for visibility only:
-
Create a Discord Channel for Informational Alerts
- Open your Discord server
- Click “+” to create a new text channel (e.g.,
#wazuh-Alerts) - Go to Channel Settings → Integrations → Webhooks
- Click “New Webhook”
- Name it (e.g.,
Wazuh-SIEM-Alerts) and copy the Webhook URL
-
Send Message Payload
Use the following JSON payload in Shuffle to post via the Discord Webhook:
{
"content": "**[Wazuh Informational Alert]**\n\n**Level:** $repeat_alert.all_fields.rule.level\n**Rule ID:** $repeat_alert.rule_id\n**Title:** $repeat_alert.all_fields.rule.description\n**Source:** $repeat_alert.all_fields.agent.name\n**Detected IP:**$repeat_alert.all_fields.agent.ip \n**Timestamp:** $repeat_alert.timestamp\n\n_No immediate action required. Logged for visibility._"
}- If alert level >= 7:
Continue to enrichment and case creation.
Create a Python script in Shuffle named severity map:
try:
rule_level = int("{{ repeat_alert.all_fields.rule.level or 0 }}")
except Exception:
rule_level = 0
# Map to IRIS severity
if rule_level < 5:
severity = 2
elif rule_level < 7:
severity = 3
elif rule_level < 10:
severity = 4
elif rule_level < 13:
severity = 5
else:
severity = 6
# IMPORTANT: Return it as `output` (Shuffle expects this)
output = {
"severity": severity
}
print(severity) # This must be returnedNote: Wazuh alerts include a severity field by default. Instead of running this script, you can directly use that value. The script above is kept here only for knowledge/reference about how severity mapping could be done manually if needed :)
- Drag IRIS into the workflow and authenticate using a new user account's API key (not the admin account).
Use the following body to create an alert:
{
"alert_title":"$repeat_alert.all_fields.rule.description",
"alert_description":"Rule ID: $repeat_alert.all_fields.rule.id\nRule Level: $repeat_alert.all_fields.rule.level\nRule Description: $repeat_alert.all_fields.rule.description\nAgent ID: $repeat_alert.all_fields.agent.id\nAgent Name: $repeat_alert.all_fields.agent.name\nMITRE IDs: $repeat_alert.all_fields.rule.mitre.id\nMITRE Tactics: $repeat_alert.all_fields.rule.mitre.tactic\nMITRE Techniques: $repeat_alert.all_fields.rule.mitre.technique\nLocation: $repeat_alert.all_fields.location",
"alert_source":"Wazuh",
"alert_source_ref":"$repeat_alert.id",
"alert_source_link":"https://192.168.18.159/app/wz-home",
"alert_severity_id":$severity_map.message,
"alert_status_id":2,
"alert_note":"Rule level: $repeat_alert.all_fields.rule.level, Event ID: $repeat_alert.all_fields.data.win.system.eventID",
"alert_tags":"wazuh,$repeat_alert.all_fields.agent.name",
"alert_customer_id":1,
"alert_source_content":""
}Cases can be created either manually by analysts or automatically.
Use this body to automate case creation in IRIS:
{
"case_customer": $create_alert.body.data.customer.customer_id,
"case_description": "$create_alert.body.data.alert_description",
"case_name": "Wazuh - $create_alert.body.data.alert_title",
"case_soc_id": "$create_alert.body.data.alert_source_ref",
"cid": "$create_alert.body.data.alert_id"
}Send alert or case summary to the SOC team via email or Discord for real-time notification.
Once alerts and cases are automatically created, you can enrich IOCs using tools like VirusTotal or MISP.
-
Via Shuffle Workflow
Use VT/MISP apps directly in your Shuffle workflow after the alert/case creation. -
Built-in IRIS Modules
- Go to IRIS → Modules
- Enable VT or MISP
- Set Auto-trigger upon IOC creation to
True - Result: Every created IOC will be automatically enriched.
Arfan Abid
LinkedIn: https://www.linkedin.com/in/arfan-abid-152217270/
