July 19, 2026
Stop Wasting Time Writing Wazuh Decoders: A Guide to Automating PCRE2 Log Parsing
If you’ve ever managed a Wazuh instance, you already know the biggest pain point: writing custom decoders and PCRE2 regular expressions for…
By Ayoub Touihri
3 min read
If you've ever managed a Wazuh instance, you already know the biggest pain point: writing custom decoders and PCRE2 regular expressions for proprietary application logs. It's a tedious, error-prone process that often feels like a dark art.
You find yourself staring at a raw log line, opening a terminal, running var/ossec/bin/wazuh-logtest, failing, tweaking a capture group, failing again, and repeating until it finally works.
Now imagine doing that for 50 different microservices, a new IoT camera, and a proprietary firewall. It's a nightmare.
But before we talk about how to automate this, we need to understand exactly why it's so difficult to get right.
How Wazuh Decoders Actually Work
To build a custom decoder, you need to understand the three core XML tags that tell Wazuh how to parse a log. Let's look at this unstructured log sample:
ERR [2023-10-10 13:55:36] User 'admin' attempted access from 172.16.0.5 but failed because password expired.ERR [2023-10-10 13:55:36] User 'admin' attempted access from 172.16.0.5 but failed because password expired.If we want Wazuh to trigger an alert on this log and extract the username and IP address, we need three things:
1. The Prematch (The Anchor)
The <prematch> tag tells Wazuh, "If the log contains this static string, use this decoder." It acts as a high-speed filter so Wazuh doesn't waste time applying regex to irrelevant logs.
<prematch>ERR</prematch><prematch>ERR</prematch>2. The Regex (The Extraction)
Wazuh uses the PCRE2 (Perl Compatible Regular Expressions) engine. You must write a PCRE2-compliant regex that uses capture groups () to pull the dynamic data out of the log.
<regex type="pcre2">User '(\S+)' from (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})</regex><regex type="pcre2">User '(\S+)' from (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})</regex>(Notice we use (\S+) to match the username, and a strict IP regex for the source IP).
3. The Order (The Mapping)
The <order> tag maps the captured groups to Wazuh's native database fields. If you map the IP to srcip, Wazuh's built-in correlation rules (like brute-force detection) will automatically trigger.
<order>user, srcip</order><order>user, srcip</order>The Problem: Scale and Syntax
Writing this for one log is easy. Writing it for hundreds of different log formats is a bottleneck.
The issue is compounded by Wazuh's strictness. If you use Python's re.escape() function to escape static text, Wazuh might throw a syntax error because its internal engine hates unnecessary backslashes. If you use greedy matches like .*, you risk ReDoS (Regular Expression Denial of Service) attacks or swallowed punctuation.
Sysadmins don't have time to become PCRE2 syntax experts just to ingest a new application log.
The Solution: A Deterministic Python Heuristic Engine
I got tired of the manual trial-and-error, so I built an open-source tool that generates the Wazuh <decoder> and <rule> XML for you in milliseconds.
Instead of relying on LLMs (which hallucinate regex syntax) or fragile re.escape() wrappers, the tool uses a Pure Python Heuristic Engine built on an "Anchor & Bridge" architecture.
The tool generates the XML and instantly simulates the extraction side-by-side in the browser.
How the Anchor & Bridge Architecture Works
- The Anchor: The engine scans the log and finds the first solid alphanumeric word (e.g.,
ERR,PAN-TRAFFIC). This becomes the<prematch>. - Dynamic Field Identification: It uses Python heuristics to identify IPs, Key-Value pairs, quoted strings, and MAC addresses.
- The Bridge (.*?): Instead of trying to perfectly escape all the static text between your dynamic fields, it bridges the gap using PCRE2 non-greedy matching (.*?). This tells the regex engine, "Skip any characters until you find the next field." It completely eliminates punctuation-swallowing bugs and syntax errors.
Proving It: The Wazuh Lab Test
I didn't just want a browser tool that spits out XML; I wanted to guarantee it works in the actual engine.
Here is the output of /var/ossec/bin/wazuh-logtest after injecting the generated XML into a live Wazuh Manager. Notice how Phase 2 cleanly extracts the fields, and Phase 3 fires the custom rule without falling back to generic syslog.
The Killer Feature: Bulk Log Analysis
Writing decoders one by one is still slow. The tool includes a Bulk Processing tab.
You can paste 1,000 raw logs at once. The engine analyzes the structural signatures of the logs, groups them by pattern, and identifies the top 3 most common log formats in your environment. It then provides a one-click button to generate the decoder for each pattern.
Why Run It Locally?
Security engineers know that pasting proprietary logs into a random browser-based tool is a massive OPSEC risk.
This tool runs 100% locally via Docker. No data ever leaves your network. There are no API keys to manage, no LLM costs, and zero privacy concerns.
Get Started
The tool is free and open-source. You can spin up your own local instance with a single command.
Features Include:
- Bulk Log Analysis (Group 1,000 logs into top patterns)
- Instant In-App Extraction Simulation
- Native Wazuh field mapping (
srcip,user,dstip) - Zero LLM Hallucinations (Pure Python Heuristics)
- 100% Local Docker Deployment
GitHub Repo: https://github.com/21Yeet21/wazuh-auto-generator
Linkedin: https://github.com/21Yeet21/wazuh-auto-generator
I'd love feedback from other SOC analysts or sysadmins on how to improve the regex logic. Fork it, test it, and let me know what logs break the engine!