<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dolan</title>
    <description>The latest articles on DEV Community by Dolan (@0xdolan).</description>
    <link>https://dev.to/0xdolan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F765234%2F7d10c25c-7194-485c-9372-10405b936778.jpg</url>
      <title>DEV Community: Dolan</title>
      <link>https://dev.to/0xdolan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/0xdolan"/>
    <language>en</language>
    <item>
      <title>Why Wazuh Missed React2Shell</title>
      <dc:creator>Dolan</dc:creator>
      <pubDate>Sun, 28 Dec 2025 08:36:59 +0000</pubDate>
      <link>https://dev.to/0xdolan/why-wazuh-missed-react2shell-59jm</link>
      <guid>https://dev.to/0xdolan/why-wazuh-missed-react2shell-59jm</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The security community was recently shaken by React2Shell, a critical unauthenticated Remote Code Execution (RCE) vulnerability. It was initially tracked under two CVEs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;CVE-2025-55182&lt;/code&gt; – React&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;CVE-2025-66478&lt;/code&gt; – Next.js&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With a CVSS score of 10.0, this vulnerability impacts Next.js 15/16 (App Router) and any framework relying on React 19’s RSC implementation.&lt;/p&gt;

&lt;p&gt;Wazuh published a great blog explaining how to detect this vulnerability:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://wazuh.com/blog/detecting-next-js-cve-2025-66478-rce-vulnerability-with-wazuh/" rel="noopener noreferrer"&gt;https://wazuh.com/blog/detecting-next-js-cve-2025-66478-rce-vulnerability-with-wazuh/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, after doing deeper research, I found a critical limitation that applies not only to this CVE, but to most modern application stacks.&lt;/p&gt;

&lt;p&gt;The Detection Gap: Why SIEMs Are Blind to Local Projects&lt;br&gt;
Standard vulnerability detectors (including Wazuh’s default modules) excel at finding packages installed via system managers like &lt;code&gt;apt&lt;/code&gt; or &lt;code&gt;npm install -g&lt;/code&gt;. But modern development happens elsewhere:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node.js:&lt;/strong&gt; Most projects install dependencies locally in the project folder.&lt;br&gt;
&lt;strong&gt;Python:&lt;/strong&gt; Virtual environments (&lt;code&gt;venv&lt;/code&gt;, &lt;code&gt;uv&lt;/code&gt;) isolate packages from the system.&lt;br&gt;
&lt;strong&gt;Docker:&lt;/strong&gt; Packages are buried inside container layers &lt;code&gt;(/var/lib/docker/...)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If your SIEM isn't looking at these local paths, you are flying blind.&lt;/p&gt;

&lt;p&gt;So if a vulnerable version of Next.js or React exists inside a project directory, Wazuh will miss it.&lt;/p&gt;

&lt;p&gt;I explained this problem earlier here:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://dev.to/0xdolan/why-you-shouldnt-rely-solely-on-detectors-373g"&gt;https://dev.to/0xdolan/why-you-shouldnt-rely-solely-on-detectors-373g&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wazuh provides several features that help, but none fully solve this problem.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;IT Hygiene / Vulnerability Detection&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://documentation.wazuh.com/current/getting-started/use-cases/it-hygiene.html#it-hygiene" rel="noopener noreferrer"&gt;https://documentation.wazuh.com/current/getting-started/use-cases/it-hygiene.html#it-hygiene&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://documentation.wazuh.com/current/user-manual/capabilities/vulnerability-detection/index.html" rel="noopener noreferrer"&gt;https://documentation.wazuh.com/current/user-manual/capabilities/vulnerability-detection/index.html&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detects globally installed packages only&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Misses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Local Node.js projects&lt;/li&gt;
&lt;li&gt;Python venvs&lt;/li&gt;
&lt;li&gt;Docker containers&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;File Integrity Monitoring (FIM)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://documentation.wazuh.com/current/user-manual/capabilities/file-integrity/index.html" rel="noopener noreferrer"&gt;https://documentation.wazuh.com/current/user-manual/capabilities/file-integrity/index.html&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detects file changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Does NOT extract:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Package names&lt;/li&gt;
&lt;li&gt;Versions&lt;/li&gt;
&lt;li&gt;Vulnerability status&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Command Monitoring&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://documentation.wazuh.com/current/user-manual/capabilities/command-monitoring/how-it-works.html" rel="noopener noreferrer"&gt;https://documentation.wazuh.com/current/user-manual/capabilities/command-monitoring/how-it-works.html&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can run scripts from the Wazuh manager&lt;/li&gt;
&lt;li&gt;High risk&lt;/li&gt;
&lt;li&gt;If manager is compromised → full agent compromise&lt;/li&gt;
&lt;li&gt;Not recommended for frequent scans&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I needed a safer and more accurate approach.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Solution: A Custom Inventory Workflow
&lt;/h2&gt;

&lt;p&gt;We can’t rely on static scanners. Instead, we need a proactive script that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Crawls the filesystem for &lt;code&gt;package.json&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;Extracts version data for specific high-risk libraries (&lt;code&gt;React/Next.js&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Logs these to a &lt;code&gt;JSON&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Feeds that file into &lt;code&gt;Wazuh&lt;/code&gt; for real-time alerting.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Step 1: The Inventory Script
&lt;/h2&gt;

&lt;p&gt;We use a Python script designed to be lightweight. Crucially, it &lt;strong&gt;does not&lt;/strong&gt; exclude &lt;code&gt;/var/lib/docker&lt;/code&gt;, allowing us to find vulnerable libraries inside container images.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Save as &lt;code&gt;/usr/local/bin/scan_react2shell.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env python3&lt;/span&gt;

import json
import os
import sys
import &lt;span class="nb"&gt;time&lt;/span&gt;

&lt;span class="c"&gt;# --- CONFIGURATION ---&lt;/span&gt;
LOG_FILE &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/var/log/react2shell_scan.json"&lt;/span&gt;
SEARCH_PATHS &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

&lt;span class="c"&gt;# Excludes (Docker paths are NOT excluded so we can scan them)&lt;/span&gt;
EXCLUDE_DIRS &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"/proc"&lt;/span&gt;, &lt;span class="s2"&gt;"/sys"&lt;/span&gt;, &lt;span class="s2"&gt;"/dev"&lt;/span&gt;, &lt;span class="s2"&gt;"/run"&lt;/span&gt;, &lt;span class="s2"&gt;"/tmp"&lt;/span&gt;, &lt;span class="s2"&gt;"/snap"&lt;/span&gt;, &lt;span class="s2"&gt;"/boot"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;


def scan_system&lt;span class="o"&gt;()&lt;/span&gt;:
    print&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"[*] Starting Inventory Scan on: {SEARCH_PATHS}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;# Initialize Log File&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;not os.path.exists&lt;span class="o"&gt;(&lt;/span&gt;LOG_FILE&lt;span class="o"&gt;)&lt;/span&gt;:
        try:
            with open&lt;span class="o"&gt;(&lt;/span&gt;LOG_FILE, &lt;span class="s2"&gt;"w"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; as f:
                pass
            print&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"[*] Created new log file at {LOG_FILE}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        except IOError as e:
            print&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"[!] Error creating log file: {e}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return

    &lt;/span&gt;count_inspected &lt;span class="o"&gt;=&lt;/span&gt; 0

    &lt;span class="k"&gt;for &lt;/span&gt;root_dir &lt;span class="k"&gt;in &lt;/span&gt;SEARCH_PATHS:
        &lt;span class="k"&gt;for &lt;/span&gt;dirpath, dirnames, filenames &lt;span class="k"&gt;in &lt;/span&gt;os.walk&lt;span class="o"&gt;(&lt;/span&gt;root_dir, &lt;span class="nv"&gt;followlinks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;True&lt;span class="o"&gt;)&lt;/span&gt;:
            &lt;span class="c"&gt;# Skip excluded directories&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;any&lt;span class="o"&gt;(&lt;/span&gt;exclude &lt;span class="k"&gt;in &lt;/span&gt;dirpath &lt;span class="k"&gt;for &lt;/span&gt;exclude &lt;span class="k"&gt;in &lt;/span&gt;EXCLUDE_DIRS&lt;span class="o"&gt;)&lt;/span&gt;:
                dirnames[:] &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
                &lt;span class="k"&gt;continue

            if&lt;/span&gt; &lt;span class="s2"&gt;"package.json"&lt;/span&gt; &lt;span class="k"&gt;in &lt;/span&gt;filenames:
                parent_dir &lt;span class="o"&gt;=&lt;/span&gt; os.path.basename&lt;span class="o"&gt;(&lt;/span&gt;dirpath&lt;span class="o"&gt;)&lt;/span&gt;
                grandparent_dir &lt;span class="o"&gt;=&lt;/span&gt; os.path.basename&lt;span class="o"&gt;(&lt;/span&gt;os.path.dirname&lt;span class="o"&gt;(&lt;/span&gt;dirpath&lt;span class="o"&gt;))&lt;/span&gt;

                pkg_name &lt;span class="o"&gt;=&lt;/span&gt; None

                &lt;span class="k"&gt;if &lt;/span&gt;grandparent_dir &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"node_modules"&lt;/span&gt;:
                    &lt;span class="k"&gt;if &lt;/span&gt;parent_dir &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"react"&lt;/span&gt;:
                        pkg_name &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"react"&lt;/span&gt;
                    &lt;span class="k"&gt;elif &lt;/span&gt;parent_dir &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"next"&lt;/span&gt;:
                        pkg_name &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"next"&lt;/span&gt;

                &lt;span class="k"&gt;if &lt;/span&gt;pkg_name:
                    full_path &lt;span class="o"&gt;=&lt;/span&gt; os.path.join&lt;span class="o"&gt;(&lt;/span&gt;dirpath, &lt;span class="s2"&gt;"package.json"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    try:
                        with open&lt;span class="o"&gt;(&lt;/span&gt;
                            full_path, &lt;span class="s2"&gt;"r"&lt;/span&gt;, &lt;span class="nv"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"utf-8"&lt;/span&gt;, &lt;span class="nv"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ignore"&lt;/span&gt;
                        &lt;span class="o"&gt;)&lt;/span&gt; as f:
                            data &lt;span class="o"&gt;=&lt;/span&gt; json.load&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="o"&gt;)&lt;/span&gt;
                            ver &lt;span class="o"&gt;=&lt;/span&gt; data.get&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"version"&lt;/span&gt;, &lt;span class="s2"&gt;"0.0.0"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

                            print&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"[+] Found {pkg_name} v{ver} at {full_path}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                            count_inspected +&lt;span class="o"&gt;=&lt;/span&gt; 1

                            &lt;span class="c"&gt;# --- DOCKER TAGGING LOGIC ---&lt;/span&gt;
                            display_path &lt;span class="o"&gt;=&lt;/span&gt; full_path
                            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
                                &lt;span class="s2"&gt;"/var/lib/docker"&lt;/span&gt; &lt;span class="k"&gt;in &lt;/span&gt;full_path
                                or &lt;span class="s2"&gt;"/var/lib/containerd"&lt;/span&gt; &lt;span class="k"&gt;in &lt;/span&gt;full_path
                            &lt;span class="o"&gt;)&lt;/span&gt;:
                                display_path &lt;span class="o"&gt;=&lt;/span&gt; f&lt;span class="s2"&gt;"[DOCKER] {full_path}"&lt;/span&gt;

                            log_entry &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                                &lt;span class="s2"&gt;"timestamp"&lt;/span&gt;: time.strftime&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"%Y-%m-%dT%H:%M:%S"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;,
                                &lt;span class="s2"&gt;"scan_type"&lt;/span&gt;: &lt;span class="s2"&gt;"react_inventory"&lt;/span&gt;,
                                &lt;span class="s2"&gt;"package"&lt;/span&gt;: pkg_name,
                                &lt;span class="s2"&gt;"version"&lt;/span&gt;: ver,
                                &lt;span class="s2"&gt;"path"&lt;/span&gt;: display_path,
                            &lt;span class="o"&gt;}&lt;/span&gt;

                            with open&lt;span class="o"&gt;(&lt;/span&gt;LOG_FILE, &lt;span class="s2"&gt;"a"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; as lf:
                                lf.write&lt;span class="o"&gt;(&lt;/span&gt;json.dumps&lt;span class="o"&gt;(&lt;/span&gt;log_entry&lt;span class="o"&gt;)&lt;/span&gt; + &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

                    except Exception as e:
                        pass

    print&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"[*] Scan complete. Total Packages Logged: {count_inspected}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if &lt;/span&gt;__name__ &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"__main__"&lt;/span&gt;:
    scan_system&lt;span class="o"&gt;()&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: This script scans for &lt;code&gt;package.json&lt;/code&gt; and specifically flags packages like &lt;code&gt;react&lt;/code&gt; and &lt;code&gt;next&lt;/code&gt; while identifying if they are inside a Docker path.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Sample Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"timestamp"&lt;/span&gt;:&lt;span class="s2"&gt;"2025-12-11T13:15:07"&lt;/span&gt;,&lt;span class="s2"&gt;"scan_type"&lt;/span&gt;:&lt;span class="s2"&gt;"react_inventory"&lt;/span&gt;,&lt;span class="s2"&gt;"package"&lt;/span&gt;:&lt;span class="s2"&gt;"react"&lt;/span&gt;,&lt;span class="s2"&gt;"version"&lt;/span&gt;:&lt;span class="s2"&gt;"19.2.1"&lt;/span&gt;,&lt;span class="s2"&gt;"path"&lt;/span&gt;:&lt;span class="s2"&gt;"[DOCKER]/var/lib/docker/.../node_modules/react/package.json"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"timestamp"&lt;/span&gt;:&lt;span class="s2"&gt;"2025-12-11T13:15:08"&lt;/span&gt;,&lt;span class="s2"&gt;"scan_type"&lt;/span&gt;:&lt;span class="s2"&gt;"react_inventory"&lt;/span&gt;,&lt;span class="s2"&gt;"package"&lt;/span&gt;:&lt;span class="s2"&gt;"next"&lt;/span&gt;,&lt;span class="s2"&gt;"version"&lt;/span&gt;:&lt;span class="s2"&gt;"15.4.5"&lt;/span&gt;,&lt;span class="s2"&gt;"path"&lt;/span&gt;:&lt;span class="s2"&gt;"/home/user/app/node_modules/next/package.json"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Wazuh Integration
&lt;/h2&gt;

&lt;p&gt;Once the script generates &lt;code&gt;/var/log/react2shell_scan.json&lt;/code&gt;, we need Wazuh to read it.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Configure the Agent:
&lt;/h2&gt;

&lt;p&gt;Add this to the Wazuh agent or via centralized configuration (&lt;code&gt;ossec.conf&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;localfile&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;log_format&amp;gt;&lt;/span&gt;json&lt;span class="nt"&gt;&amp;lt;/log_format&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;location&amp;gt;&lt;/span&gt;/var/log/react2shell_scan.json&lt;span class="nt"&gt;&amp;lt;/location&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/localfile&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pushing the Configuration Centrally
&lt;/h3&gt;

&lt;p&gt;To avoid manually editing the &lt;code&gt;ossec.conf&lt;/code&gt; file on every server, we utilize Wazuh’s Centralized Configuration feature. By modifying the &lt;code&gt;agent.conf&lt;/code&gt; file on the Manager, we can instruct all agents to start "watching" our custom inventory log.&lt;/p&gt;

&lt;p&gt;On the Wazuh Manager:&lt;/p&gt;

&lt;p&gt;Edit the shared configuration file for the default group:&lt;br&gt;
&lt;code&gt;vim /var/ossec/etc/shared/default/agent.conf&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Add the following block inside the  tags:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;agent_config&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- 
    This tells every agent to monitor the output of our inventory script.
    Wazuh will collect these JSON logs and send them to the manager for analysis.
  --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;localfile&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;log_format&amp;gt;&lt;/span&gt;json&lt;span class="nt"&gt;&amp;lt;/log_format&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;location&amp;gt;&lt;/span&gt;/var/log/react2shell_scan.json&lt;span class="nt"&gt;&amp;lt;/location&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/localfile&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/agent_config&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Synchronization:&lt;/strong&gt; Once you save this file on the Manager, it automatically calculates a new &lt;code&gt;MD5 checksum&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Propagation:&lt;/strong&gt; The next time your agents check in (heartbeat), they will detect the configuration change, download the updated &lt;code&gt;agent.conf&lt;/code&gt; file, and restart their log collector engine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visibility:&lt;/strong&gt; From this point forward, any time your Python script (run via cron) updates &lt;code&gt;/var/log/react2shell_scan.json&lt;/code&gt;, the data is instantly streamed to the Wazuh Manager to be checked against your custom &lt;code&gt;React2Shell&lt;/code&gt; rules.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  2. Create the Detection Rules:
&lt;/h2&gt;

&lt;p&gt;In your Wazuh Manager (&lt;code&gt;/var/ossec/etc/rules/local_rules.xml&lt;/code&gt;), add rules to flag specific vulnerable versions based on the Vercel and React security bulletins.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;group&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"react_inventory,cve_2025_55182,cve_2025_66478,vulnerability,"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- INVENTORY: Log EVERY React/Next package found--&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;rule&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"100500"&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class="nt"&gt;&amp;lt;decoded_as&amp;gt;&lt;/span&gt;json&lt;span class="nt"&gt;&amp;lt;/decoded_as&amp;gt;&lt;/span&gt; 
    &lt;span class="nt"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"scan_type"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;react_inventory&lt;span class="nt"&gt;&amp;lt;/field&amp;gt;&lt;/span&gt; 
    &lt;span class="nt"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;Inventory: Found $(package) version $(version) at $(path).&lt;span class="nt"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt; 
  &lt;span class="nt"&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Detect Vulnerable React.js --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;rule&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"100501"&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"15"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;if_sid&amp;gt;&lt;/span&gt;100500&lt;span class="nt"&gt;&amp;lt;/if_sid&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"package"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;react&lt;span class="nt"&gt;&amp;lt;/field&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"version"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"pcre2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    ^19\.0\.0$|^19\.1\.[0-1]$|^19\.2\.0$
  &lt;span class="nt"&gt;&amp;lt;/field&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;info&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"cve"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;CVE-2025-55182&lt;span class="nt"&gt;&amp;lt;/info&amp;gt;&lt;/span&gt; 
  &lt;span class="nt"&gt;&amp;lt;info&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"link"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;https://nvd.nist.gov/vuln/detail/CVE-2025-55182&lt;span class="nt"&gt;&amp;lt;/info&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;Vulnerable React2Shell detected: React $(version) at $(path)&lt;span class="nt"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;mitre&amp;gt;&amp;lt;id&amp;gt;&lt;/span&gt;T1190&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&amp;lt;/mitre&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;


  &lt;span class="c"&gt;&amp;lt;!-- Detect Vulnerable Next.js --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;rule&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"100502"&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"15"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class="nt"&gt;&amp;lt;if_sid&amp;gt;&lt;/span&gt;100500&lt;span class="nt"&gt;&amp;lt;/if_sid&amp;gt;&lt;/span&gt; 
    &lt;span class="nt"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"package"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;next&lt;span class="nt"&gt;&amp;lt;/field&amp;gt;&lt;/span&gt;  
    &lt;span class="nt"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"version"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"pcre2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;^15\.(0\.[0-4]|1\.[0-8]|2\.[0-5]|3\.[0-5]|4\.[0-7]|5\.[0-6])$|^16\.0\.[0-6]$&lt;span class="nt"&gt;&amp;lt;/field&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;info&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"cve"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;CVE-2025-66478&lt;span class="nt"&gt;&amp;lt;/info&amp;gt;&lt;/span&gt; 
  &lt;span class="nt"&gt;&amp;lt;info&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"link"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;https://nvd.nist.gov/vuln/detail/CVE-2025-66478&lt;span class="nt"&gt;&amp;lt;/info&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;Vulnerable React2Shell detected: Next.js $(version) at $(path)&lt;span class="nt"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt; 
    &lt;span class="nt"&gt;&amp;lt;mitre&amp;gt;&amp;lt;id&amp;gt;&lt;/span&gt;T1190&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&amp;lt;/mitre&amp;gt;&lt;/span&gt; 
  &lt;span class="nt"&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/group&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Deployment via Ansible
&lt;/h2&gt;

&lt;p&gt;How do you get this onto 100 servers? &lt;strong&gt;Don't use Wazuh's "Command Monitoring" for script execution.&lt;/strong&gt; Giving a SIEM manager the right to run arbitrary scripts on all agents is a major security risk if the manager is compromised.&lt;/p&gt;

&lt;p&gt;Instead, use Ansible. Create a playbook to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Copy the Python script.&lt;/li&gt;
&lt;li&gt;Set up a Cron job (e.g., daily at 2 AM).&lt;/li&gt;
&lt;li&gt;Ensure the log file permissions are correct.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Notifications / Messenger Integration
&lt;/h3&gt;

&lt;p&gt;To receive real-time alerts in your favorite messenger app, you can use these community integrations:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fltt8sxvlpsqo2ps93u29.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fltt8sxvlpsqo2ps93u29.jpg" alt="Wazuh-Telegram-Slack-Teams" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Slack: &lt;a href="https://github.com/0xdolan/wazuh-slack-integration" rel="noopener noreferrer"&gt;https://github.com/0xdolan/wazuh-slack-integration&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Telegram: &lt;a href="https://github.com/0xdolan/wazuh-telegram-integration" rel="noopener noreferrer"&gt;https://github.com/0xdolan/wazuh-telegram-integration&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Microsoft Teams: &lt;a href="https://github.com/0xdolan/wazuh-teams-integration" rel="noopener noreferrer"&gt;https://github.com/0xdolan/wazuh-teams-integration&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By shifting from "System Inventory" to "Application Inventory," we caught a CVSS 10.0 vulnerability that otherwise would have stayed hidden in a local &lt;code&gt;node_modules&lt;/code&gt; folder.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>node</category>
      <category>nextjs</category>
      <category>react</category>
    </item>
    <item>
      <title>Why You Shouldn’t Rely Solely on Detectors</title>
      <dc:creator>Dolan</dc:creator>
      <pubDate>Mon, 08 Dec 2025 20:16:28 +0000</pubDate>
      <link>https://dev.to/0xdolan/why-you-shouldnt-rely-solely-on-detectors-373g</link>
      <guid>https://dev.to/0xdolan/why-you-shouldnt-rely-solely-on-detectors-373g</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F584i0wos3ze5slqmzzll.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F584i0wos3ze5slqmzzll.png" alt=" " width="800" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently, vulnerabilities like &lt;strong&gt;CVE-2025-55182&lt;/strong&gt; and &lt;strong&gt;CVE-2025-66478&lt;/strong&gt; have raised alarms for Next.js and React developers. If you're using Wazuh for vulnerability detection, there’s an important limitation you need to understand: project-local installs of npm packages might &lt;strong&gt;not&lt;/strong&gt; be detected by default.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why Wazuh Might Miss Vulnerable Packages
&lt;/h3&gt;

&lt;p&gt;Wazuh’s vulnerability detection relies heavily on the &lt;strong&gt;Syscollector&lt;/strong&gt; module, which scans installed software. Here’s the catch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Global npm packages&lt;/strong&gt; (&lt;code&gt;npm install -g&lt;/code&gt;) are detected automatically. Standard paths include:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/usr/lib/node_modules
/usr/local/lib/node_modules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;C:\Program&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Files\nodejs\node_modules&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;C:\Users\USER\AppData\Roaming\npm\node_modules&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local project installs&lt;/strong&gt; (normal &lt;code&gt;node_modules&lt;/code&gt; inside your project) &lt;strong&gt;are NOT scanned by default&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/var/www/project/node_modules
/home/user/app/node_modules
/app/node_modules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://documentation.wazuh.com/current/user-manual/capabilities/system-inventory/compatibility-matrix.html" rel="noopener noreferrer"&gt;According to Wazuh documentation&lt;/a&gt;, support for scanning NPM and PyPI packages is limited to default installation paths. The developers have confirmed that scanning arbitrary project folders is &lt;strong&gt;not planned&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This means that if your Next.js or React project has a vulnerable package installed locally, Wazuh may miss it entirely unless you take extra steps.&lt;/p&gt;




&lt;h3&gt;
  
  
  What You Can Do
&lt;/h3&gt;

&lt;p&gt;Even if Syscollector won’t detect project-local packages, you can leverage &lt;strong&gt;File Integrity Monitoring (FIM)&lt;/strong&gt; and &lt;strong&gt;custom log collection&lt;/strong&gt; to track changes and spot potential risks:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Monitor Your Project Folder with FIM
&lt;/h4&gt;

&lt;p&gt;Add a custom path in &lt;code&gt;/var/ossec/etc/ossec.conf&lt;/code&gt; to monitor your project directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;syscheck&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;directories&lt;/span&gt; &lt;span class="na"&gt;realtime=&lt;/span&gt;&lt;span class="s"&gt;"yes"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;/var/www/myapp&lt;span class="nt"&gt;&amp;lt;/directories&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/syscheck&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows Wazuh to track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;File creations, deletions, and modifications&lt;/li&gt;
&lt;li&gt;Changes in &lt;code&gt;node_modules/&lt;/code&gt; or config files&lt;/li&gt;
&lt;li&gt;Suspicious additions or tampering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://documentation.wazuh.com/current/user-manual/capabilities/file-integrity/basic-settings.html" rel="noopener noreferrer"&gt;More details in the Wazuh FIM guide&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Collect Logs from Build or Deployment
&lt;/h4&gt;

&lt;p&gt;You can log your &lt;code&gt;npm install&lt;/code&gt; and &lt;code&gt;npm audit&lt;/code&gt; outputs and let Wazuh collect them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;localfile&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;location&amp;gt;&lt;/span&gt;/var/www/myapp/install_deps.log&lt;span class="nt"&gt;&amp;lt;/location&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;log_format&amp;gt;&lt;/span&gt;syslog&lt;span class="nt"&gt;&amp;lt;/log_format&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/localfile&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;localfile&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;location&amp;gt;&lt;/span&gt;/var/www/myapp/build.log&lt;span class="nt"&gt;&amp;lt;/location&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;log_format&amp;gt;&lt;/span&gt;syslog&lt;span class="nt"&gt;&amp;lt;/log_format&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/localfile&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;npm install &amp;gt; install_deps.log&lt;/code&gt; in your build pipeline&lt;/li&gt;
&lt;li&gt;Optionally, run &lt;code&gt;npm audit --json &amp;gt; audit.log&lt;/code&gt; and collect it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, create &lt;strong&gt;custom decoders and rules&lt;/strong&gt; in Wazuh to alert you when known vulnerable packages are installed or modified.&lt;/p&gt;




&lt;h3&gt;
  
  
  Key Takeaways
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Don’t rely solely on vulnerability detectors&lt;/strong&gt; like Wazuh Syscollector for project-local npm installs.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;FIM and log collection&lt;/strong&gt; to monitor your codebase and dependencies.&lt;/li&gt;
&lt;li&gt;Regularly run &lt;strong&gt;&lt;code&gt;npm audit&lt;/code&gt; or third-party scanners&lt;/strong&gt; like Snyk, etc. as part of your CI/CD pipeline.&lt;/li&gt;
&lt;li&gt;Always combine &lt;strong&gt;automated detection&lt;/strong&gt; with &lt;strong&gt;good monitoring practices&lt;/strong&gt; for robust security coverage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://wazuh.com/blog/detecting-next-js-cve-2025-66478-rce-vulnerability-with-wazuh/" rel="noopener noreferrer"&gt;For more details on Wazuh CVE detection for Next.js, check out&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;By combining these approaches, you ensure that even project-local dependencies don’t slip under the radar, keeping your Next.js and React apps safer.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Posted with ❤️ by 0xdolan | &lt;a href="https://github.com/0xdolan" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>nextjs</category>
      <category>react</category>
      <category>wazuh</category>
    </item>
    <item>
      <title>Watch Out for These Slash-Like Unicode Characters in Phishing Links</title>
      <dc:creator>Dolan</dc:creator>
      <pubDate>Wed, 20 Aug 2025 16:25:11 +0000</pubDate>
      <link>https://dev.to/0xdolan/watch-out-for-these-slash-like-unicode-characters-in-phishing-links-3po1</link>
      <guid>https://dev.to/0xdolan/watch-out-for-these-slash-like-unicode-characters-in-phishing-links-3po1</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyz72x34pwsiwdaef77n8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyz72x34pwsiwdaef77n8.jpg" alt=" " width="800" height="1422"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Phishing attacks are getting sneakier, and sometimes all it takes is a &lt;strong&gt;single Unicode character&lt;/strong&gt; to fool even a trained eye. One of the newest phishing techniques involves &lt;strong&gt;swapping the regular &lt;code&gt;/&lt;/code&gt; (slash)&lt;/strong&gt; with a similar-looking Unicode character.&lt;/p&gt;

&lt;p&gt;Visually? Everything looks normal.&lt;br&gt;&lt;br&gt;
Under the hood? The link is &lt;strong&gt;not what you think&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s take a look 👇&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 Phishing with Unicode: Slash Lookalikes
&lt;/h2&gt;

&lt;p&gt;Attackers exploit Unicode to &lt;strong&gt;mimic legitimate URLs&lt;/strong&gt; by swapping out the slash &lt;code&gt;/&lt;/code&gt; with &lt;strong&gt;homoglyphs&lt;/strong&gt; — characters that &lt;em&gt;look&lt;/em&gt; the same but are actually different.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Character&lt;/th&gt;
&lt;th&gt;Unicode&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Hover Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;td&gt;U+002F&lt;/td&gt;
&lt;td&gt;Solidus (Normal Slash)&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com/" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;∖&lt;/td&gt;
&lt;td&gt;U+2216&lt;/td&gt;
&lt;td&gt;Set Minus (Backslash-like)&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%E2%88%96" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⁄&lt;/td&gt;
&lt;td&gt;U+2044&lt;/td&gt;
&lt;td&gt;Fraction Slash&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%E2%81%84" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;∕&lt;/td&gt;
&lt;td&gt;U+2215&lt;/td&gt;
&lt;td&gt;Division Slash&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%E2%88%95" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⧸&lt;/td&gt;
&lt;td&gt;U+29F8&lt;/td&gt;
&lt;td&gt;Big Solidus&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%E2%A7%B8" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;／&lt;/td&gt;
&lt;td&gt;U+FF0F&lt;/td&gt;
&lt;td&gt;Fullwidth Solidus&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%EF%BC%8F" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;︐&lt;/td&gt;
&lt;td&gt;U+FE10&lt;/td&gt;
&lt;td&gt;Presentation Form for Vertical Comma&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%EF%B8%90" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;〳&lt;/td&gt;
&lt;td&gt;U+3033&lt;/td&gt;
&lt;td&gt;Vertical Kana Repeat Mark Upper&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%E3%80%B3" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;㇓&lt;/td&gt;
&lt;td&gt;U+31D3&lt;/td&gt;
&lt;td&gt;CJK Stroke-like Character&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%E3%87%93" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ん&lt;/td&gt;
&lt;td&gt;U+3093&lt;/td&gt;
&lt;td&gt;Hiragana Letter N (used in phishing)&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%E3%82%93" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;׃&lt;/td&gt;
&lt;td&gt;U+05C3&lt;/td&gt;
&lt;td&gt;Hebrew Punctuation Sof Pasuq&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%D7%83" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;܁&lt;/td&gt;
&lt;td&gt;U+0701&lt;/td&gt;
&lt;td&gt;Syriac Supralinear Full Stop&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%DC%81" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;᜵&lt;/td&gt;
&lt;td&gt;U+1735&lt;/td&gt;
&lt;td&gt;Philippine Single Punctuation&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%E1%9C%B5" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;፡&lt;/td&gt;
&lt;td&gt;U+1361&lt;/td&gt;
&lt;td&gt;Ethiopic Wordspace&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%E1%8D%A1" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;•&lt;/td&gt;
&lt;td&gt;U+2022&lt;/td&gt;
&lt;td&gt;Bullet&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%E2%80%A2" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;＼&lt;/td&gt;
&lt;td&gt;U+FF3C&lt;/td&gt;
&lt;td&gt;Fullwidth Reverse Solidus (Backslash)&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%EF%BC%BC" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;᠆&lt;/td&gt;
&lt;td&gt;U+1806&lt;/td&gt;
&lt;td&gt;Mongolian Todo Soft Hyphen&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%E1%A0%86" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⁂&lt;/td&gt;
&lt;td&gt;U+2042&lt;/td&gt;
&lt;td&gt;Asterism&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%E2%81%82" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⸻&lt;/td&gt;
&lt;td&gt;U+2E3B&lt;/td&gt;
&lt;td&gt;Two-Em Dash&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%E2%B8%BB" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⹝&lt;/td&gt;
&lt;td&gt;U+2E5D&lt;/td&gt;
&lt;td&gt;Oblique Hyphen&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%E2%B9%9D" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;…&lt;/td&gt;
&lt;td&gt;U+2026&lt;/td&gt;
&lt;td&gt;Ellipsis&lt;/td&gt;
&lt;td&gt;&lt;a href="https://booking.com%E2%80%A6" rel="noopener noreferrer"&gt;https://booking.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xunqln94ad3bt5ctynb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xunqln94ad3bt5ctynb.jpg" alt=" " width="800" height="937"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🛡️ Why This Matters
&lt;/h2&gt;

&lt;p&gt;Phishing pages crafted this way can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bypass visual inspection&lt;/li&gt;
&lt;li&gt;Evade some automated filters&lt;/li&gt;
&lt;li&gt;Trick users into trusting a malicious link&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hovering over links or inspecting the full URL is no longer enough unless you're looking for &lt;strong&gt;non-standard characters&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  More on This
&lt;/h2&gt;

&lt;p&gt;This phishing method has been &lt;strong&gt;spotted in the wild&lt;/strong&gt;, including in a campaign targeting &lt;strong&gt;Booking.com customers&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;📰 Read the full breakdown here:&lt;br&gt;&lt;br&gt;
👉 &lt;a href="https://www.bleepingcomputer.com/news/security/bookingcom-phishing-campaign-uses-sneaky-character-to-trick-you/" rel="noopener noreferrer"&gt;Booking.com phishing campaign uses sneaky character to trick you&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🎬 Watch the analysis by John Hammond:&lt;br&gt;&lt;br&gt;
👉 &lt;a href="https://www.youtube.com/watch?v=nxVr4ERhrPQ" rel="noopener noreferrer"&gt;YouTube: John Hammond Explains the Unicode Phishing Trick&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Stay sharp and stay safe. Just because a link &lt;em&gt;looks&lt;/em&gt; right, doesn’t mean it &lt;em&gt;is&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;💬 Have you seen similar techniques in the wild? Share below!&lt;/p&gt;

</description>
      <category>security</category>
      <category>phishing</category>
      <category>unicode</category>
      <category>awareness</category>
    </item>
    <item>
      <title>Wazuh 4.12 Slack Alert Integration</title>
      <dc:creator>Dolan</dc:creator>
      <pubDate>Wed, 06 Aug 2025 05:43:04 +0000</pubDate>
      <link>https://dev.to/0xdolan/wazuh-412-slack-alert-integration-3fm9</link>
      <guid>https://dev.to/0xdolan/wazuh-412-slack-alert-integration-3fm9</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx2ap4qgxitfaou2hdamu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx2ap4qgxitfaou2hdamu.jpg" alt="Wazuh Slack Integration" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wazuh is a powerful open-source security platform for threat detection and response. This guide walks you through creating a custom integration script to send Wazuh alerts directly to Slack channels.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Wazuh ships with a default &lt;code&gt;slack.py&lt;/code&gt; script located at &lt;code&gt;/var/ossec/integrations&lt;/code&gt;, but it’s generic and may not meet specific formatting or channel-routing needs. In this guide, we’ll build a tailored solution from scratch.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiaqgutzjlaw3vmucd8kk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiaqgutzjlaw3vmucd8kk.jpg" alt="Wazuh Slack Alert Sample" width="800" height="1422"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;h2&gt;
  
  
  🛠️ Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A Slack workspace with three channels and their webhooks:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;critical&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;high&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;medium&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Wazuh 4.12 installed&lt;/li&gt;
&lt;li&gt;Basic knowledge of Linux shell and Python&lt;/li&gt;
&lt;/ul&gt;



&lt;h2&gt;
  
  
  🔧 Create a Slack Workspace and Channels
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://slack.com/help/articles/206845317-Create-a-Slack-workspace" rel="noopener noreferrer"&gt;Create a Slack Workspace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://slack.com/help/articles/201402297-Create-a-channel" rel="noopener noreferrer"&gt;Create a Slack Channel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://api.slack.com/messaging/webhooks" rel="noopener noreferrer"&gt;Enable Incoming Webhooks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your Slack webhook URL will look like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Make sure your webhook URLs are structured like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2nisrjtc452fe1oe8y9s.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2nisrjtc452fe1oe8y9s.jpg" alt="Webhooks" width="672" height="327"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;h2&gt;
  
  
  📦 Step 1: Set up Python Virtual Environment in Wazuh
&lt;/h2&gt;

&lt;p&gt;Create a Python virtual environment inside the Wazuh directory (&lt;code&gt;/var/ossec&lt;/code&gt;) to avoid permission issues and package conflicts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /var/ossec/venv
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv /var/ossec/venv
&lt;span class="nb"&gt;source&lt;/span&gt; /var/ossec/venv/bin/activate
pip &lt;span class="nb"&gt;install &lt;/span&gt;requests  &lt;span class="c"&gt;# or any needed packages&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  📁 Step 2: Create Slack Integration Script
&lt;/h2&gt;

&lt;p&gt;Name the script with prefix &lt;code&gt;custom-&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Location:&lt;/strong&gt; &lt;code&gt;/var/ossec/integrations/custom-slack.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/var/ossec/venv/bin/python
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="c1"&gt;# Slack webhook URLs (Critical, High, Medium)
&lt;/span&gt;&lt;span class="n"&gt;WEBHOOK_CRITICAL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;  &lt;span class="c1"&gt;# replace with your Critical channel webhook
&lt;/span&gt;&lt;span class="n"&gt;WEBHOOK_HIGH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;  &lt;span class="c1"&gt;# replace with your High channel webhook
&lt;/span&gt;&lt;span class="n"&gt;WEBHOOK_MEDIUM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;  &lt;span class="c1"&gt;# replace with your Medium channel webhook
&lt;/span&gt;
&lt;span class="c1"&gt;# Excluded Wazuh Rule IDs
&lt;/span&gt;&lt;span class="n"&gt;excluded_rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;  &lt;span class="c1"&gt;# Example: ["1002", "5715", "18107"]
&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;escape_markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Escapes characters used by Slack markdown to avoid unintended formatting.
    Only *, _, `, and ~ are special in Slack and need escaping.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Escape only Slack formatting characters: *, _, `, and ~
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;([*`_~])&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\\\1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;choose_webhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;lvl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;WEBHOOK_MEDIUM&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lvl&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;WEBHOOK_CRITICAL&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;lvl&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;WEBHOOK_HIGH&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;WEBHOOK_MEDIUM&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[ERROR] No alert file path provided.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;alert_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alert_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;alert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[ERROR] Failed to read or parse JSON: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;rule_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rule&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rule_id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;excluded_rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[INFO] Skipping excluded rule ID: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;rule_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
    &lt;span class="n"&gt;srcuser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;srcuser&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dstuser&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;srcip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;srcip&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;srcport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;srcport&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;agent_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;alert_level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rule&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;level&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rule&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;full_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;full_log&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No full log available&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;timestamp_raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;dt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromisoformat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timestamp_raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Z&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+00:00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%Y-%m-%d %H:%M:%S&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;timestamp_raw&lt;/span&gt;

    &lt;span class="c1"&gt;# Build Slack message with block formatting
&lt;/span&gt;    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*:rotating_light: Wazuh Alert Notification*&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*Time:* `&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*Username:* `&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;srcuser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*Source IP:* `&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;srcip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*Source Port:* `&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;srcport&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*Agent:* `&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*Rule ID:* `&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rule_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*Level:* `&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alert_level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*Description:*&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;    &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*Full Log:*&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;    &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;full_log&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;vuln&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vulnerability&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
    &lt;span class="n"&gt;cve_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vuln&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cve&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cve_title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vuln&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cve_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;cve_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://cti.wazuh.com/vulnerabilities/cves/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cve_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;*🛡️ CVE:* `&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cve_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*Title:* &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cve_title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cve_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;|Details in CTI&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;────────────────────────&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;webhook_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;choose_webhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alert_level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webhook_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[ERROR] Slack response: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; – &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🔧 Step 3: Create Shell Wrapper Script
&lt;/h2&gt;

&lt;p&gt;Wazuh calls shell scripts, so create a simple wrapper to call the Python script. It should have the same name of the python file without the &lt;code&gt;.py&lt;/code&gt; extension.&lt;br&gt;
&lt;strong&gt;Location:&lt;/strong&gt; &lt;code&gt;/var/ossec/integrations/custom-slack&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="c"&gt;# Set the virtual environment Python binary&lt;/span&gt;
&lt;span class="nv"&gt;CUSTOM_PYTHON&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/ossec/venv/bin/python3"&lt;/span&gt;

&lt;span class="nv"&gt;SCRIPT_PATH_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;DIR_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SCRIPT_PATH_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;pwd&lt;/span&gt; &lt;span class="nt"&gt;-P&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;SCRIPT_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SCRIPT_PATH_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;PYTHON_SCRIPT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DIR_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SCRIPT_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.py"&lt;/span&gt;

&lt;span class="c"&gt;# Run the integration script using custom Python interpreter&lt;/span&gt;
&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CUSTOM_PYTHON&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PYTHON_SCRIPT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make both scripts executable and set proper ownership:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;750 /var/ossec/integrations/custom-slack&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="nb"&gt;chown &lt;/span&gt;root:wazuh /var/ossec/integrations/custom-slack&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Configure Integration in &lt;code&gt;ossec.conf&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ensure that &lt;code&gt;logall_json&lt;/code&gt; is enabled by setting it to &lt;code&gt;yes&lt;/code&gt; in your &lt;code&gt;ossec.conf&lt;/code&gt; file:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ossec_config&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;global&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;jsonout_output&amp;gt;&lt;/span&gt;yes&lt;span class="nt"&gt;&amp;lt;/jsonout_output&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;alerts_log&amp;gt;&lt;/span&gt;yes&lt;span class="nt"&gt;&amp;lt;/alerts_log&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;logall&amp;gt;&lt;/span&gt;yes&lt;span class="nt"&gt;&amp;lt;/logall&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;logall_json&amp;gt;&lt;/span&gt;yes&lt;span class="nt"&gt;&amp;lt;/logall_json&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/global&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ossec_config&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add the integration block in &lt;code&gt;/var/ossec/etc/ossec.conf&lt;/code&gt;:&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt; tag value (&lt;code&gt;custom-slack&lt;/code&gt;) must exactly match the name of your wrapper script.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ossec_config&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;integration&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;custom-slack&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;alert_format&amp;gt;&lt;/span&gt;json&lt;span class="nt"&gt;&amp;lt;/alert_format&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/integration&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ossec_config&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart Wazuh to apply changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl restart wazuh-manager.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ✅ Step 6: Test the Integration
&lt;/h2&gt;

&lt;p&gt;Test manually with an alert JSON file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/var/ossec/integrations/custom-slack /var/ossec/logs/alerts/alerts.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Related Projects
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/0xdolan/wazuh-telegram-integration" rel="noopener noreferrer"&gt;Wazuh Telegram Integration&lt;/a&gt; – Send Wazuh alerts to Telegram using a similar method.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🚀 Result
&lt;/h2&gt;

&lt;p&gt;You’ll begin receiving real-time Slack alerts for all critical, high, and medium-level events. Each alert is detailed, well-formatted, and clearly marked by severity, helping you respond faster and more effectively.&lt;/p&gt;

&lt;p&gt;If you found this useful or have questions, feel free to comment. Happy monitoring! 👨‍💻📱&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Created with ❤️ by 0xdolan | &lt;a href="https://github.com/0xdolan" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://github.com/0xdolan/wazuh-slack-integration/blob/main/README.md" rel="noopener noreferrer"&gt;View this guide on GitHub&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>wazuh</category>
      <category>slack</category>
      <category>cybersecurity</category>
      <category>siem</category>
    </item>
    <item>
      <title>Wazuh 4.12 Telegram Alert Integration (with SSH Login Alerts)</title>
      <dc:creator>Dolan</dc:creator>
      <pubDate>Fri, 01 Aug 2025 06:47:53 +0000</pubDate>
      <link>https://dev.to/0xdolan/wazuh-412-telegram-alert-integration-with-ssh-login-alerts-4mbd</link>
      <guid>https://dev.to/0xdolan/wazuh-412-telegram-alert-integration-with-ssh-login-alerts-4mbd</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcxv68ilpvh2vu3fad32q.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcxv68ilpvh2vu3fad32q.jpg" alt="Wazuh Telegram Integration" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wazuh is a robust open-source security platform, but it doesn't include native support for Telegram alerts. This guide walks you through a simple method to send alerts, like SSH login attempts, to Telegram using a custom integration script.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbf3yux2u21engju4o065.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbf3yux2u21engju4o065.jpg" alt="Wazuh Telegram Alert Sample" width="800" height="999"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🛠️ Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A Telegram bot and your chat ID (&lt;a href="https://core.telegram.org/bots#6-botfather" rel="noopener noreferrer"&gt;official guide&lt;/a&gt;, or use the quick setup below)&lt;/li&gt;
&lt;li&gt;Wazuh 4.12 installed&lt;/li&gt;
&lt;li&gt;Basic Linux shell and Python knowledge&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  How to Create a Telegram Bot
&lt;/h1&gt;

&lt;p&gt;Creating a Telegram bot is quick and easy with Telegram’s official &lt;strong&gt;BotFather&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open Telegram and search for &lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/botfather"&gt;@botfather&lt;/a&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Start a conversation and send &lt;code&gt;/start&lt;/code&gt; to begin.&lt;/li&gt;
&lt;li&gt;Create your bot with the command &lt;code&gt;/newbot&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Follow the instructions:

&lt;ul&gt;
&lt;li&gt;Provide a display name for your bot.&lt;/li&gt;
&lt;li&gt;Choose a unique username that ends with &lt;code&gt;bot&lt;/code&gt; (e.g., &lt;code&gt;WazuhAlertBot&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;BotFather will then return your &lt;strong&gt;bot token&lt;/strong&gt;, which looks like this: &lt;code&gt;123456789:ABCdefGhIJKlmNoPQRstUVwxyz1234567890&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Keep this token safe, it's required to send messages from your bot.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can now find your bot on Telegram using its username and send it a message to start.&lt;/p&gt;




&lt;h1&gt;
  
  
  How to Get Your Telegram Chat ID
&lt;/h1&gt;

&lt;p&gt;To send alerts to Telegram, you'll need your &lt;strong&gt;chat ID&lt;/strong&gt;. The script below fetches your chat ID by reading the latest message sent to your bot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Replace the &lt;code&gt;bot_token&lt;/code&gt; in the script with the token you got from BotFather.&lt;/li&gt;
&lt;li&gt;Send any message to your bot via Telegram (e.g., "hello").&lt;/li&gt;
&lt;li&gt;Run the script below using Python.&lt;/li&gt;
&lt;li&gt;Your chat ID will be printed in the terminal.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Python Script to Retrieve Chat ID
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;bot_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;  &lt;span class="c1"&gt;# Replace with your bot token
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_chat_id&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.telegram.org/bot&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bot_token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/getUpdates&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Get chat ID from the last message
&lt;/span&gt;            &lt;span class="n"&gt;chat_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Your Chat ID is: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;chat_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No messages found. Please send a message to your bot first.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to get updates: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;get_chat_id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📦 Step 1: Set up Python Virtual Environment in Wazuh
&lt;/h2&gt;

&lt;p&gt;Create a Python virtual environment inside the Wazuh directory (&lt;code&gt;/var/ossec&lt;/code&gt;) to avoid permission issues and package conflicts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /var/ossec/venv
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv /var/ossec/venv
&lt;span class="nb"&gt;source&lt;/span&gt; /var/ossec/venv/bin/activate
pip &lt;span class="nb"&gt;install &lt;/span&gt;requests  &lt;span class="c"&gt;# or any needed packages&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  📁 Step 2: Create Telegram Integration Script
&lt;/h2&gt;

&lt;p&gt;Name the script with prefix &lt;code&gt;custom-&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Location:&lt;/strong&gt; &lt;code&gt;/var/ossec/integrations/custom-telegram.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/var/ossec/venv/bin/python
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="c1"&gt;# Telegram Bot credentials
&lt;/span&gt;&lt;span class="n"&gt;bot_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;  &lt;span class="c1"&gt;# Replace with your Telegram bot token
&lt;/span&gt;&lt;span class="n"&gt;chat_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;  &lt;span class="c1"&gt;# Replace with your Telegram chat ID
&lt;/span&gt;
&lt;span class="c1"&gt;# === Excluded Wazuh Rule IDs ===
&lt;/span&gt;&lt;span class="n"&gt;excluded_rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;  &lt;span class="c1"&gt;# Example: ["1002", "5715", "18107"]
&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;escape_markdown_v2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Escape special MarkdownV2 characters
&lt;/span&gt;    &lt;span class="n"&gt;escape_chars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;_*[]()~`&amp;gt;#+-=|{}.!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;([%s])&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;escape_chars&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\\\1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[ERROR] No alert file path provided.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;alert_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alert_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;alert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[ERROR] Failed to read or parse alert JSON file: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;rule_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rule&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rule_id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;excluded_rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[INFO] Skipping excluded rule ID: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;rule_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Extract fields
&lt;/span&gt;    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
    &lt;span class="n"&gt;srcuser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;srcuser&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dstuser&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;srcport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;srcport&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;srcip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;srcip&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;agent_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;alert_level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rule&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;level&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;rule_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rule&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rule&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;full_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;full_log&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No full log available&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;timestamp_raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Convert timestamp to human readable format (date and time to seconds)
&lt;/span&gt;    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Try parsing ISO8601 format
&lt;/span&gt;        &lt;span class="n"&gt;dt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromisoformat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timestamp_raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Z&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+00:00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%Y-%m-%d %H:%M:%S&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;timestamp_raw&lt;/span&gt;  &lt;span class="c1"&gt;# fallback if parsing fails
&lt;/span&gt;
    &lt;span class="c1"&gt;# Build message
&lt;/span&gt;    &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*🚨 Wazuh Alert Notification*&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🕒 *Time:* `&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown_v2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;👤 *Username:* `&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown_v2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;srcuser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🌐 *Source IP:* `&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown_v2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;srcip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🚪 *Source Port:* `&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown_v2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;srcport&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;💻 *Agent:* &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown_v2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🆔 *Rule ID:* `&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown_v2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rule_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🧱 *Level:* *&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown_v2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alert_level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;📄 *Description:*&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown_v2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🔍 *Full Log:*&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown_v2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;full_log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;vuln&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vulnerability&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
    &lt;span class="n"&gt;cve_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vuln&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cve&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cve_title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vuln&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cve_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://cti.wazuh.com/vulnerabilities/cves/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cve_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cve_id&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cve_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;*🛡️ CVE:* `&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown_v2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cve_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*📄 Details:* &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown_v2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cve_title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[🔗 View in CTI](&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;escape_markdown_v2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cve_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Send to Telegram
&lt;/span&gt;    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.telegram.org/bot&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bot_token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/sendMessage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;chat_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;parse_mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MarkdownV2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[ERROR] Telegram response: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; - &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🔧 Step 3: Create Shell Wrapper Script
&lt;/h2&gt;

&lt;p&gt;Wazuh calls shell scripts, so create a simple wrapper to call the Python script. It should have the same name of the python file without the &lt;code&gt;.py&lt;/code&gt; extension.&lt;br&gt;
&lt;strong&gt;Location:&lt;/strong&gt; &lt;code&gt;/var/ossec/integrations/custom-telegram&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
/var/ossec/venv/bin/python3 /var/ossec/integrations/custom-telegram.py &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make both scripts executable and set proper ownership:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;750 /var/ossec/integrations/custom-telegram&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="nb"&gt;chown &lt;/span&gt;root:wazuh /var/ossec/integrations/custom-telegram&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Configure Integration in &lt;code&gt;ossec.conf&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ensure that &lt;code&gt;logall_json&lt;/code&gt; is enabled by setting it to &lt;code&gt;yes&lt;/code&gt; in your &lt;code&gt;ossec.conf&lt;/code&gt; file:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ossec_config&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;global&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;jsonout_output&amp;gt;&lt;/span&gt;yes&lt;span class="nt"&gt;&amp;lt;/jsonout_output&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;alerts_log&amp;gt;&lt;/span&gt;yes&lt;span class="nt"&gt;&amp;lt;/alerts_log&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;logall&amp;gt;&lt;/span&gt;yes&lt;span class="nt"&gt;&amp;lt;/logall&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;logall_json&amp;gt;&lt;/span&gt;yes&lt;span class="nt"&gt;&amp;lt;/logall_json&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/global&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ossec_config&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add the integration block in &lt;code&gt;/var/ossec/etc/ossec.conf&lt;/code&gt;:&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt; tag value (&lt;code&gt;custom-telegram&lt;/code&gt;) must exactly match the name of your wrapper script.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ossec_config&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;integration&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;custom-telegram&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;level&amp;gt;&lt;/span&gt;7&lt;span class="nt"&gt;&amp;lt;/level&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;alert_format&amp;gt;&lt;/span&gt;json&lt;span class="nt"&gt;&amp;lt;/alert_format&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/integration&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ossec_config&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setting level to &lt;code&gt;7&lt;/code&gt; means only alerts with level 7 or higher trigger the Telegram alert.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔒 Step 5: Elevate SSH Login Rule Level in Wazuh
&lt;/h2&gt;

&lt;p&gt;By default, successful SSH login events (SID &lt;code&gt;5715&lt;/code&gt;) have a low alert level and do not trigger integrations. To resolve this, create or update the file &lt;code&gt;/var/ossec/etc/rules/local_rules.xml&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;group&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"local,syslog,sshd,"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;rule&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"100011"&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"7"&lt;/span&gt; &lt;span class="na"&gt;overwrite=&lt;/span&gt;&lt;span class="s"&gt;"yes"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;if_sid&amp;gt;&lt;/span&gt;5715&lt;span class="nt"&gt;&amp;lt;/if_sid&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;sshd: Successful SSH login with elevated level.&lt;span class="nt"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;group&amp;gt;&lt;/span&gt;authentication_success,pci_dss_10.2.5,&lt;span class="nt"&gt;&amp;lt;/group&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/group&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration overrides the level of rule ID 5715 and raises it to level 7, ensuring it triggers and sends alerts to Telegram.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔗 &lt;a href="https://documentation.wazuh.com/current/user-manual/ruleset/ruleset-xml-syntax/rules.html#rule" rel="noopener noreferrer"&gt;Rules Syntax — Wazuh rule definitions and structure&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After making these changes, restart the Wazuh manager to apply them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl restart wazuh-manager
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ✅ Step 6: Test the Integration
&lt;/h2&gt;

&lt;p&gt;Test manually with an alert JSON file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/var/ossec/integrations/custom-telegram /var/ossec/logs/alerts/alerts.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or wait for a real SSH login alert to be sent to Telegram.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Projects
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/0xdolan/wazuh-slack-integration" rel="noopener noreferrer"&gt;Wazuh Slack Integration&lt;/a&gt; – Send Wazuh alerts to Slack using a similar method.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🚀 Result
&lt;/h2&gt;

&lt;p&gt;Receive real-time Telegram alerts for SSH logins and other critical events with detailed, nicely formatted messages, perfect for quick incident response.&lt;/p&gt;

&lt;p&gt;If you found this useful or have questions, feel free to comment. Happy monitoring! 👨‍💻📱&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Created with ❤️ by 0xdolan | &lt;a href="https://github.com/0xdolan" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://github.com/0xdolan/wazuh-telegram-integration/blob/main/README.md" rel="noopener noreferrer"&gt;View this guide on GitHub&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>wazuh</category>
      <category>telegram</category>
      <category>cybersecurity</category>
      <category>siem</category>
    </item>
  </channel>
</rss>
