S Shamar Bryant
Projects Skills Certifications About Resume Contact
Email LinkedIn
Home/Projects/AI SOC Triage
SOC AutomationAI SecurityPythonSIEM

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.

CategorySOC Automation · AI Security · Python
ToolsPython, OpenAI API, Wazuh Indexer (OpenSearch), Rocky Linux, PowerShell
RoleDesigned, built, troubleshot, and documented end to end
StatusFunctional, run on demand
SkillsSIEM 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.

Windows / Linux Hosts (Wazuh agents)

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:

  1. Checked Xen Orchestra. The Wazuh VM existed but was powered off. Started it.
  2. Opened the VM console. Logged in as user shamar on Rocky Linux (hostname wazuh1). Confirmed sudo access.
  3. Ran ip addr. The eth0 interface was present but had no IPv4 address assigned.
  4. Ran ip route. The routing table was completely empty.
  5. Checked NetworkManager. nmcli device status showed eth0 as disconnected. A saved profile named eth0 existed but was not active.
  6. Inspected the profile. nmcli connection show eth0 | grep ipv4 revealed a valid static config: 172.22.3.49/22, gateway 172.22.0.1. The configuration was correct, just inactive.
Rocky Linux · NetworkManager
# Activate the existing connection profile sudo nmcli connection up eth0 Connection successfully activated # Verify IP assignment ip addr show eth0 inet 172.22.3.49/22 brd 172.22.3.255 scope global eth0 # Set autoconnect so it survives reboots sudo nmcli connection modify eth0 connection.autoconnect yes

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/.

triage_alert.py · core workflow
# Load alert with open("alert.json", "r") as f: alert = json.load(f) # Extract key fields summary = { "agent": alert.get("agent", {}).get("name"), "rule_desc": alert["rule"]["description"], "level": alert["rule"]["level"], "mitre": alert.get("rule", {}).get("mitre", {}) } # Send to OpenAI response = client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": "You are a SOC analyst..."}, {"role": "user", "content": json.dumps(summary)} ] )

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.

Indexer query · latest alert
query = { "size": 1, "sort": [{"@timestamp": {"order": "desc"}}], "query": {"match_all": {}} } response = requests.post( f"{INDEXER_URL}/wazuh-alerts-*/_search", auth=(INDEXER_USER, INDEXER_PASS), json=query, verify=False # self-signed cert in lab )

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

Problem

Wazuh VM unreachable. Ping, SSH, and browser access all failed.

Fix

The VM was powered off. Started it via Xen Orchestra, then activated the inactive NetworkManager profile with nmcli connection up eth0.

Problem

The network fix did not survive reboot. Wazuh became unreachable again after restart.

Fix

Set connection.autoconnect yes on the eth0 profile so it activates automatically at boot.

Problem

PowerShell blocked venv activation: running scripts is disabled on this system.

Fix

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass, which changes only the current session.

Problem

OpenAI returned RateLimitError: insufficient_quota immediately after the first request.

Fix

ChatGPT Plus and the OpenAI API are billed separately. Added API credits to the account and it resolved immediately.

Problem

Port 9200 timed out from Windows. The Indexer was bound only to localhost.

Fix

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.

Problem

Wazuh API credentials on port 55000 kept returning 401 despite multiple attempts.

Fix

Found installer-generated credentials at /root/wazuh-install-files/wazuh-passwords.txt. The dashboard config credentials were not valid for direct API auth.

Results

8
Wazuh agents reporting telemetry
100%
Automated, no manual alert export
2
Scripts, manual and automated

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/
Example output: for a PAM login session alert (Rule Level 3, MITRE T1078 Valid Accounts), the AI correctly classified the event as likely benign, explained the process context, noted the MITRE technique relevance, and provided recommended next verification steps.

Skills Demonstrated

Linux AdministrationNetworkManager / nmcliIP Addressing & Routing Virtualization (Xen)SIEM ConceptsWazuh Indexer API PythonREST API IntegrationJSON Parsing OpenAI APIAlert TriageMITRE ATT&CK Python venvCredential ManagementMethodical Troubleshooting

Planned Next Steps

  • Add a --limit N option 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