Wazuh-LLM Cisco Network Incident Response
Automated network incident response system for Cisco IOS-XE routers and switches. Takes Wazuh SIEM alerts, classifies them with a fine-tuned LLM, queries live device state via RESTCONF, generates CLI fix commands using domain-specific LoRA adapters, and applies the fixes automatically via RESTCONF PATCH.
Two backends are provided: a manual 3-script pipeline for operator-controlled workflows, and a fully autonomous daemon that watches Wazuh logs and resolves incidents end-to-end without human intervention.
Architecture
Backend 1 β Manual Pipeline (3 scripts)
Wazuh alerts file
|
v
[runners/prefilter.py] filter level-12, drop auth noise
|
v
[runners/pipeline.py]
Stage 1 Wazuh LLM (Ollama) incident_type, severity, IOCs
Stage 2 Show command lookup deterministic table (incident -> show cmds)
Stage 3 RESTCONF mapping deterministic table (show cmd -> YANG path)
Stage 4 Domain routing selects correct LoRA adapter
|
v creates show_outputs/alert_NNN_DEVICE_INCIDENT/
restconf_commands.json <- execute these GETs against routers
alert_info.json
(operator executes RESTCONF GETs and drops response JSONs into the folder)
|
v
[runners/run_fix.py] polls folders, runs domain LoRA
|
|-- fix_commands.txt CLI fix commands (human readable)
+-- restconf_fix_commands.json RESTCONF PATCH ops to apply the fix
+-- pipeline_fix_output.jsonl full record of all alerts processed
Backend 2 β Autonomous Daemon (always-on)
/var/ossec/logs/alerts/alerts.json (Wazuh live output, tailed continuously)
|
v
[backend/daemon.py]
Watch tail alerts file, detect new entries (level 7-12)
Detect SSH brute-force: 5+ failures from same IP within 5-minute window
|
v per alert, fully automatic:
[1] Extract device IP -> device map
[2] Classify Ollama wazuh-llama -> incident_type, IOCs, severity
[3] Show commands deterministic table lookup
[4] RESTCONF GETs execute live against device, collect YANG state
[5] Domain LoRA generate CLI fix commands
[6] RESTCONF PATCHes apply fixes directly to device
[7] Log result managed_incidents.jsonl + managed_incidents.log
|
v per-alert folder:
restconf_get_results.json what the device reported
fix_commands.txt CLI commands the LLM generated
restconf_fix_commands.json PATCH ops with YANG bodies
patch_results.json HTTP status of each PATCH
LoRA Adapters
18 domain-specific adapters fine-tuned on Hermes-3-Llama-3.1-8B (r=8, alpha=32):
| Domain | Adapter | Incidents covered |
|---|---|---|
| OSPF | incidents/ospf/ospf1 |
Neighbor down, full-to-down, adjacency loss |
| OSPF | incidents/ospf/ospf2 |
ExStart/Exchange stuck, Init stuck, 2-Way |
| OSPF | incidents/ospf/ospf3 |
Auth, hello/dead mismatch, area, network-type, MTU |
| OSPF | incidents/ospf/ospf4 |
LSA flood, LSDB inconsistency, redistribution |
| BGP | incidents/bgp/lora_llm_bgp1 |
Session flap, hold-timer expiry, neighbor reset |
| BGP | incidents/bgp/lora_llm_bgp2 |
Prefix limit, route leak, path selection |
| BGP | incidents/bgp/lora_llm_bgp3 |
Missing RIB routes, next-hop-self, AFI-SAFI mismatch |
| Sec | incidents/security/lora_llm_sec1 |
ACL blocking legitimate traffic |
| Sec | incidents/security/lora_llm_sec2 |
ACL misconfiguration (protocol, wildcard, direction) |
| Sec | incidents/security/lora_llm_sec3 |
Excessive denies, brute force, port scan |
| Switch | incidents/switch/lora_llm_switch1 |
MAC flapping, STP topology change, err-disable |
| Switch | incidents/switch/lora_llm_switch2 |
Port security, duplex/speed mismatch |
| Switch | incidents/switch/lora_llm_switch3 |
VLAN mismatch, trunk negotiation, storm control |
| Service | incidents/service/lora_llm_service1 |
DHCP conflict, starvation, IP conflict |
| Service | incidents/service/lora_llm_service2 |
DNS failure, NTP unsync, ARP spoofing |
| Sys | incidents/sys/lora_llm_sys1 |
High CPU, memory exhaustion, process crash |
| Sys | incidents/sys/lora_llm_sys2 |
Interface flap, duplex/speed mismatch |
| Sys | incidents/sys/lora_llm_sys3 |
Reload, environmental, general system health |
Requirements
pip install -r requirements.txt
The Wazuh LLM stage uses Ollama with a local wazuh-llama model:
# Install Ollama: https://ollama.com
ollama create wazuh-llama -f Modelfile
Quick Start β Manual Pipeline
# Step 1 β pre-filter raw Wazuh export
python runners/prefilter.py --input alerts.json --output s_alerts.jsonl
# Step 2 β classify + build RESTCONF show commands + create per-alert folders
python runners/pipeline.py --input s_alerts.jsonl --show-dir show_outputs
# Step 3 β execute the RESTCONF GETs listed in each folder's restconf_commands.json
# and save JSON responses into the same folder
# Step 4 β run domain LoRA, generate fix commands + RESTCONF PATCH ops
python runners/run_fix.py --show-dir show_outputs
Per-alert output folder after all steps:
show_outputs/alert_001_R1_ospf_neighbor_down/
alert_info.json alert metadata
restconf_commands.json GET commands (written by pipeline.py)
show_ip_ospf_neighbor.json RESTCONF GET response (you drop this)
fix_commands.txt CLI fix commands (written by run_fix.py)
restconf_fix_commands.json RESTCONF PATCH ops (written by run_fix.py)
Quick Start β Autonomous Daemon
# Standard β watch live Wazuh alerts, auto-apply fixes (level 7-12)
python backend/daemon.py
# Dry run β classify + generate commands, but do NOT PATCH devices
python backend/daemon.py --dry-run
# Custom alert file and thresholds
python backend/daemon.py \
--alerts /var/ossec/logs/alerts/alerts.json \
--min-level 7 \
--ssh-threshold 5 \
--ssh-window 300 \
--poll 3
The daemon tail-follows the Wazuh alerts file and processes each alert automatically end-to-end with no operator involvement.
Daemon output files
| File | Content |
|---|---|
managed_incidents.jsonl |
Machine-readable: one JSON record per handled alert |
managed_incidents.log |
Human-readable: one summary block per alert |
daemon.log |
Full debug log of all daemon activity |
show_outputs/alert_NNN_*/ |
Per-alert audit folder (GET results, fix, patch results) |
SSH Brute-Force Detection
The daemon tracks failed SSH login alerts independently of the level filter.
When 5 or more failures from the same source IP occur within 5 minutes,
a synthetic ssh_brute_force incident is triggered and the full pipeline runs β
even if each individual alert is below the level threshold.
Tune with --ssh-threshold N --ssh-window SECONDS.
Device Configuration
Edit the maps at the top of runners/pipeline.py and backend/daemon.py to match your network:
SOURCE_IP_DEVICE_MAP = {
"10.10.10.10": "R1",
"2.2.2.2": "R2",
# ...
}
DEVICE_MGMT_IP = {
"R1": "10.10.10.10", # management IP used for RESTCONF
"R2": "2.2.2.2",
# ...
}
Router credentials: ROUTER_USER / ROUTER_PASS constants (default: admin / cisco123!).
RESTCONF
All communication uses RESTCONF over HTTPS (port 443) with Cisco IOS-XE YANG models.
Read (GET) β _RESTCONF_RULES table maps each show command to its YANG path:
show ip ospf neighbor -> /restconf/data/Cisco-IOS-XE-ospf-oper:ospf-oper-data/ospf-state
show ip bgp summary -> /restconf/data/Cisco-IOS-XE-bgp-oper:bgp-state-data/bgp-route-vrfs
show interfaces -> /restconf/data/Cisco-IOS-XE-interfaces-oper:interfaces
...
Write (PATCH) β CLI fix commands are parsed into context blocks and converted to RESTCONF PATCH operations with YANG-native JSON bodies:
interface GigabitEthernet0/0 -> PATCH .../interface/GigabitEthernet=0%2F0
ip ospf hello-interval 10 body: Cisco-IOS-XE-ospf:ospf hello-interval 10
router bgp 65001 -> PATCH .../router/bgp=65001
neighbor 10.0.0.2 timers 30 90 body: neighbor timers keepalive 30 holdtime 90
ip access-list extended INBOUND -> PATCH .../ip/access-list/extended=INBOUND
Supported YANG modules include:
Cisco-IOS-XE-ospf-oper, Cisco-IOS-XE-bgp-oper, Cisco-IOS-XE-interfaces-oper,
Cisco-IOS-XE-acl-oper, Cisco-IOS-XE-spanning-tree-oper, Cisco-IOS-XE-vlan-oper,
Cisco-IOS-XE-dhcp-oper, Cisco-IOS-XE-arp-oper, Cisco-IOS-XE-nat-oper,
Cisco-IOS-XE-ntp-oper, Cisco-IOS-XE-process-cpu-oper,
Cisco-IOS-XE-process-memory-oper, Cisco-IOS-XE-native
Training
Training scripts and datasets are in training/ and datasets/.
Each adapter was trained on 900β1500 examples with LoRA (r=8, alpha=32, dropout=0.1)
targeting q_proj and v_proj on Hermes-3-Llama-3.1-8B.
python training/train_ospf1.py
python training/train_bgp1.py
# etc.
Lab Topology
Tested on a 4-router + 4-switch Cisco IOS-XE lab:
- R1 / R2 / R3 / R4 β IOS-XE routers running OSPF + BGP
- SW1 / SW2 β distribution switches
- ACCESS-SW1 / ACCESS-SW2 β access switches
- R4 β DHCP server (192.168.40.0/24 pool)
- Wazuh manager collecting syslog from all devices
Project Files
| Path | Description |
|---|---|
runners/prefilter.py |
Pre-filter raw Wazuh export (level filter + brute-force detection) |
runners/pipeline.py |
Manual backend Phase 1: classify, map RESTCONF GETs, create folders |
runners/run_fix.py |
Manual backend Phase 2: run domain LoRA, generate and map fix commands |
backend/daemon.py |
Autonomous daemon: watches live Wazuh alerts, resolves incidents end-to-end |
Modelfile |
Ollama model definition for the Wazuh alert classifier |
models/base/ |
Hermes-3-Llama-3.1-8B base model |
models/incidents/ |
18 domain-specific LoRA adapters |
models/registry.json |
Adapter name -> path registry |
datasets/ |
Training datasets (JSONL, one incident type per file) |
training/ |
Training scripts (one per adapter) |
cases/ |
Incident test cases used for evaluation |
Citation
@misc{wazuh-llm-cisco-2025,
title = {Wazuh-LLM Cisco Network Incident Response},
year = {2025},
url = {https://huggingface.co/YOUR_USERNAME/wazuh-llm-cisco}
}
- Downloads last month
- -
4-bit
Model tree for JoeiBanana/ai-network-llms
Base model
meta-llama/Llama-3.1-8B