AI-Powered SOC Alert Triage System
A Python SOC analyst assistant that retrieves live security alerts from a Wazuh SIEM indexer, extracts MITRE ATT&CK context, and generates analyst-style triage reports with OpenAI.
| Category | SOC Automation · AI Security · Python |
| Tools | Python, OpenAI API, Wazuh Indexer (OpenSearch), Rocky Linux, PowerShell |
| Role | Designed, built, troubleshot, and documented end to end |
| Status | Functional, run on demand |
| Skills | SIEM integration, API auth, JSON parsing, Python automation, AI triage, Linux admin, networking |
Problem
The goal was to build a practical project that combines live SIEM telemetry with AI-assisted alert triage. Rather than simulate data, the project required connecting to a working SIEM environment and automating the analyst workflow: retrieve an alert, understand its context, and produce a structured triage report.
The specific challenge was this: how do you take raw security event data from a live SIEM, extract the meaningful fields, and produce something that reads like a trained analyst's assessment, automatically and on demand?
The secondary challenge was infrastructure. Before any code could run, the lab environment needed to be fully operational, and that required real troubleshooting.
Environment
- Windows PC as the analyst workstation, 172.22.2.119
- Wazuh server VM running Rocky Linux, hostname wazuh1, 172.22.3.49
- Xen Orchestra (XOA) managing the virtualized environment
- Multiple Wazuh agents reporting telemetry from Windows and Linux endpoints
- Wazuh Indexer (OpenSearch) on port 9200 storing alert documents
- OpenAI API for AI-assisted triage
- Python project folder on the Windows analyst workstation
The SIEM dashboard showed 8 agents (6 active, 2 disconnected) with real security events, including authentication failures, MITRE ATT&CK-mapped alerts, and Windows and Linux log entries.
Final Architecture
The completed pipeline runs on demand, pulling the most recent security alert and producing a structured triage report.
↓
Wazuh Manager · wazuh1 · 172.22.3.49
↓
Wazuh Indexer · port 9200 · wazuh-alerts-*
↓
Python · triage_latest_wazuh_alert.py
↓
OpenAI API · GPT-based SOC analysis
↓
SOC Triage Report · Markdown saved to reports/
The script is run manually with python triage_latest_wazuh_alert.py. It connects to the Wazuh Indexer, queries the latest alert, extracts key fields, sends a structured summary to OpenAI, prints the triage output, and saves both the report and the raw alert JSON to disk.
Infrastructure Setup & Discovery
The project did not begin with coding. It began with infrastructure troubleshooting. The only starting information was a sticky note with IP addresses: the Wazuh server at 172.22.3.49, managed through Xen Orchestra.
Initial problem: every connection attempt to the Wazuh server failed. Ping, SSH, and browser access all returned unreachable errors.
The troubleshooting process followed a deliberate layer-by-layer approach:
- Checked Xen Orchestra. The Wazuh VM existed but was powered off. Started it.
- Opened the VM console. Logged in as user shamar on Rocky Linux (hostname wazuh1). Confirmed sudo access.
- Ran ip addr. The eth0 interface was present but had no IPv4 address assigned.
- Ran ip route. The routing table was completely empty.
- Checked NetworkManager.
nmcli device statusshowed eth0 as disconnected. A saved profile named eth0 existed but was not active. - Inspected the profile.
nmcli connection show eth0 | grep ipv4revealed a valid static config: 172.22.3.49/22, gateway 172.22.0.1. The configuration was correct, just inactive.
After restoring the network, the Wazuh dashboard became accessible at https://172.22.3.49. It showed 8 agents reporting telemetry and existing security events with MITRE ATT&CK technique mappings.
Python Automation
The Python project was created at C:\Users\shamar\ai-wazuh-triage with a virtual environment to isolate dependencies.
Phase 1, manual JSON triage. The first working script (triage_alert.py) loaded a manually exported Wazuh alert JSON, parsed key fields, sent a structured summary to OpenAI, printed the triage analysis, and saved a Markdown report to reports/.
Phase 2, automated alert retrieval. The manual export step was eliminated. The script was rewritten to connect directly to the Wazuh Indexer, query the wazuh-alerts-* index, retrieve the most recent alert by timestamp, and run the same triage process automatically.
Wazuh Indexer Integration
The Wazuh dashboard stores alert documents in the Wazuh Indexer (OpenSearch), accessible on port 9200. The Python script queries this directly to pull the latest alert.
The Indexer was initially bound only to localhost (127.0.0.1:9200). It had to be exposed to the LAN by updating /etc/wazuh-indexer/opensearch.yml to network.host: 0.0.0.0 and restarting the service. This is only appropriate in a trusted lab environment, not production.
Credentials for the Indexer were separate from the Wazuh API credentials. The correct admin credentials came from the installer-generated file at /root/wazuh-install-files/wazuh-passwords.txt.
Challenges & Fixes
Wazuh VM unreachable. Ping, SSH, and browser access all failed.
The VM was powered off. Started it via Xen Orchestra, then activated the inactive NetworkManager profile with nmcli connection up eth0.
The network fix did not survive reboot. Wazuh became unreachable again after restart.
Set connection.autoconnect yes on the eth0 profile so it activates automatically at boot.
PowerShell blocked venv activation: running scripts is disabled on this system.
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass, which changes only the current session.
OpenAI returned RateLimitError: insufficient_quota immediately after the first request.
ChatGPT Plus and the OpenAI API are billed separately. Added API credits to the account and it resolved immediately.
Port 9200 timed out from Windows. The Indexer was bound only to localhost.
Confirmed with ss -lntp | grep 9200 showing 127.0.0.1:9200. Updated opensearch.yml to network.host: 0.0.0.0 and restarted the service.
Wazuh API credentials on port 55000 kept returning 401 despite multiple attempts.
Found installer-generated credentials at /root/wazuh-install-files/wazuh-passwords.txt. The dashboard config credentials were not valid for direct API auth.
Results
The final script successfully:
- Connects to the Wazuh Indexer and retrieves the latest alert from
wazuh-alerts-* - Extracts agent name, rule description, severity level, and MITRE ATT&CK IDs and techniques
- Handles both Windows alerts (Event ID, logon type, process name) and Linux alerts (PAM, SSH, syslog)
- Sends a structured summary to OpenAI and receives an analyst-style triage
- Saves the triage report as Markdown and the raw alert as JSON to
reports/
Skills Demonstrated
Planned Next Steps
- Add a
--limit Noption to triage the latest N alerts in one run - Add severity filtering to analyze only alerts above a rule-level threshold
- Track analyzed alert IDs locally to avoid duplicate triage
- Separate Windows and Linux alert parsing for better field coverage
- Build a simple Streamlit or Flask dashboard to browse alerts and view reports
- Add email or Slack notification for high-severity findings