---
title: "Shuffle — SOAR Open Source"
domain: security
subdomain: soc
phase: 03-response
type: snippet
tags: [shuffle, soar, automation, workflow, soc, incident-response]
difficulty: intermediate
status: stable
updated: "Fri Jun 19 2026 00:00:00 GMT+0000 (Coordinated Universal Time)"
---
## Présentation

Shuffle est un SOAR (Security Orchestration, Automation and Response) open source.  
Il orchestre les réponses aux incidents via des **workflows visuels** connectant les outils SOC.

```
Trigger (Wazuh alerte)
    ↓
Workflow Shuffle
    ├─ Enrichir IOC (VirusTotal, AbuseIPDB)
    ├─ Créer case TheHive
    ├─ Notifier Slack/Teams
    └─ Bloquer IP sur pfSense (si score > 80)
```

---

## Déploiement Docker

```yaml
# docker-compose.yml
version: "3"
services:
  shuffle-frontend:
    image: ghcr.io/shuffle/shuffle-frontend:latest
    ports:
      - "3001:80"
    environment:
      - BACKEND_HOSTNAME=shuffle-backend

  shuffle-backend:
    image: ghcr.io/shuffle/shuffle-backend:latest
    ports:
      - "5001:5001"
    volumes:
      - shuffle-apps:/shuffle-apps
      - shuffle-db:/shuffle-db
      - /var/run/docker.sock:/var/run/docker.sock  # Pour exécuter les apps Docker
    environment:
      - DATASTORE_EMULATOR_HOST=shuffle-database:8000
      - SHUFFLE_APP_HOTLOAD_FOLDER=/shuffle-apps
      - SHUFFLE_FILE_LOCATION=/shuffle-db
      - OUTER_HOSTNAME=shuffle-backend
      - ORG_ID=default
      - SHUFFLE_OPENSEARCH_URL=http://shuffle-opensearch:9200

  shuffle-orborus:
    image: ghcr.io/shuffle/shuffle-orborus:latest
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - SHUFFLE_APP_SDK_TIMEOUT=300
      - ENVIRONMENT_NAME=Shuffle
      - ORG_ID=default
      - BASE_URL=http://shuffle-backend:5001

  shuffle-opensearch:
    image: opensearchproject/opensearch:2.14.0
    environment:
      - discovery.type=single-node
      - DISABLE_SECURITY_PLUGIN=true
      - "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
    volumes:
      - shuffle-opensearch:/usr/share/opensearch/data

volumes:
  shuffle-apps:
  shuffle-db:
  shuffle-opensearch:
```

```
# Accès : http://localhost:3001
# Créer compte admin au premier démarrage
```

---

## Concepts clés

```
App      → Connecteur vers un outil (TheHive, Wazuh, VirusTotal...)
Action   → Opération spécifique d'une App (créer case, chercher hash...)
Workflow → Séquence d'Actions connectées visuellement
Trigger  → Déclencheur du workflow (webhook, schedule, email, manual)
```

---

## Apps à installer

```
# Apps officielles disponibles dans l'App Store Shuffle
Wazuh          → Gestion alertes, agents
TheHive        → Case management
MISP           → IOC lookup, création d'events
OpenCTI        → Enrichissement threat intel
VirusTotal     → Analyse hash, IP, URL, domain
AbuseIPDB      → Score réputation IP
Shodan         → Info host
Slack / Teams  → Notifications
pfSense        → Blocage IP (via API)
Email          → Notifications, phishing response
HTTP           → Appels API génériques
```

---

## Workflow — Triage d'alerte Wazuh

```yaml
# Workflow : Wazuh Alert → Enrichissement → TheHive → Notification

Trigger : Webhook (Wazuh envoie l'alerte)
  URL : http://shuffle-backend:5001/api/v1/hooks/HOOK_ID

Step 1 : Parse Alert
  Action : Regex/JSON extract
  Extract : src_ip, rule_id, agent_name, timestamp

Step 2 : VirusTotal IP Check
  App : VirusTotal
  Action : Get IP report
  Input : $exec.src_ip
  Output : vt_score, vt_categories

Step 3 : AbuseIPDB Check
  App : AbuseIPDB
  Action : Check IP
  Input : $exec.src_ip
  Output : abuse_score, country

Step 4 : Condition — Score élevé ?
  IF vt_score > 5 OR abuse_score > 50
    → Step 5 (créer case)
  ELSE
    → Step 6 (log et terminer)

Step 5 : Créer Case TheHive
  App : TheHive
  Action : Create Case
  Input :
    title: "Wazuh Alert: $exec.rule_description"
    severity: 2
    tags: ["wazuh", "rule-$exec.rule_id"]

Step 6 : Notifier Slack
  App : Slack
  Action : Send message
  Channel : #soc-alerts
  Message : "🚨 Alert $exec.rule_id on $exec.agent_name — IP $exec.src_ip (Abuse: $abuse_score%)"
```

---

## Intégration Wazuh → Shuffle (webhook)

```python
# /var/ossec/integrations/custom-shuffle
#!/usr/bin/env python3
import json, sys, requests

def send_to_shuffle(alert):
    url = "http://shuffle-backend:5001/api/v1/hooks/HOOK_ID"
    headers = {"Content-Type": "application/json"}
    requests.post(url, json=alert, headers=headers, verify=False)

alert = json.loads(sys.stdin.read())
send_to_shuffle(alert)
```

```xml
<!-- /var/ossec/etc/ossec.conf -->
<integration>
  <name>custom-shuffle</name>
  <level>7</level>
  <alert_format>json</alert_format>
</integration>
```

---

## Workflow — Réponse phishing

```
Trigger : Email reçu (IMAP polling ou forwarding)
  ↓
Extract : URLs, pièces jointes, expéditeur
  ↓
URLScan.io : analyser chaque URL
  ↓
VirusTotal : analyser pièces jointes (hash)
  ↓
IF malveillant détecté :
  → Créer case TheHive (severity: 3)
  → Exporter domaines malveillants vers MISP
  → Bloquer domaine sur pfSense DNS
  → Notifier utilisateur ciblé + DSI
  ↓
IF score faible :
  → Log dans TheHive (sans escalade)
```

---

## Workflow — Blocage IP automatique

```
Trigger : TheHive case créé avec tag "block-ip"
  ↓
Extract : observable IP du case
  ↓
AbuseIPDB check : score > 80 ?
  ↓
pfSense API : POST /api/v1/firewall/alias/entry
  Body : { name: "BLACKLIST_SOC", address: "$ip" }
  ↓
TheHive : Ajouter task log "IP $ip bloquée sur pfSense"
  ↓
Slack : "#soc-response → IP $ip bloquée automatiquement"
```

---

## API Shuffle

```bash
BASE_URL="http://localhost:5001"
API_KEY="shuffle_api_key"

# Lister les workflows
curl -H "Authorization: Bearer $API_KEY" \
  $BASE_URL/api/v1/workflows

# Déclencher un workflow manuellement
curl -X POST \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ip": "185.220.101.45"}' \
  $BASE_URL/api/v1/hooks/HOOK_ID

# Lister les exécutions
curl -H "Authorization: Bearer $API_KEY" \
  $BASE_URL/api/v1/workflows/WORKFLOW_ID/executions
```
