Skip to content

modsecurity parser fails to match valid Apache ModSecurity logs #1607

@Etilem

Description

@Etilem

Note: This bug was identified and fixed by Claude Code (Opus 4.5) during a debugging session.

Bug Report: ModSecurity Parser Fails to Match Apache Error Logs

Summary

The crowdsecurity/modsecurity parser (v1.3) fails to parse valid Apache ModSecurity log entries due to a space handling bug in the grok patterns APACHEERRORPREFIX2 and MODSECPREFIX2.

Environment

  • CrowdSec version: 1.6.x
  • Parser version: crowdsecurity/modsecurity v1.3
  • OS: Debian 13 (Trixie)
  • Apache version: 2.4.x with mod_security2
  • ModSecurity CRS: 3.3.7

Symptoms

  • ModSecurity logs are read from /var/log/apache2/error.log but never parsed
  • cscli explain --type modsecurity shows parser failure
  • cscli metrics show parsers shows 0 hits for crowdsecurity/modsecurity
  • Attackers triggering ModSecurity rules are never banned

Root Cause Analysis

The bug is in the space handling between two patterns:

Pattern 1: APACHEERRORPREFIX2

\\[%{APACHEERRORTIME:timestamp}\\] \\[%{NOTSPACE:apacheseverity}\\] (\\[pid %{INT}(:tid %{INT})?\\] )?\\[(client|remote) %{IPORHOST:sourcehost}(:%{INT:source_port})?\\] (\\[client %{IPORHOST}\\])?

Note the ending: \\] (\\[client %{IPORHOST}\\])?

There is a space before the optional [client IP] group.

Pattern 2: MODSECPREFIX2

%{APACHEERRORPREFIX2} ModSecurity: ...

Note: There is a space after %{APACHEERRORPREFIX2}.

The Problem

For a log line like:

[Mon Dec 15 05:34:22 2025] [security2:error] [pid 123:tid 456] [client 192.168.1.1:12345] ModSecurity: Warning...
  1. APACHEERRORPREFIX2 matches up to [client 192.168.1.1:12345]
  2. After the closing ], there's a space in the log
  3. The pattern ] (\\[client ...) consumes that space while trying to match the optional group
  4. The optional group (\\[client %{IPORHOST}\\])? fails (next chars are ModSecurity, not [client)
  5. Since it's optional, the group is skipped, but the space was already consumed
  6. MODSECPREFIX2 then expects another space before ModSecurity:
  7. But the space was already consumed, so the match fails

Fix

Move the space inside the optional group, so it's only consumed when the group actually matches:

Before (broken)

APACHEERRORPREFIX2: "...\\] (\\[client %{IPORHOST}\\])?"
MODSECPREFIX2: "%{APACHEERRORPREFIX2} ModSecurity: ..."

After (fixed)

APACHEERRORPREFIX2: "...\\] (\\[client %{IPORHOST}\\] )?"
MODSECPREFIX2: "%{APACHEERRORPREFIX2}ModSecurity: ..."

Changes:

  1. Add space inside optional group: (\\[client %{IPORHOST}\\])?(\\[client %{IPORHOST}\\] )?
  2. Remove space after prefix: %{APACHEERRORPREFIX2} ModSecurity:%{APACHEERRORPREFIX2}ModSecurity:

Verification

Before fix

$ echo '[Mon Dec 15 05:34:22 2025] [security2:error] [pid 123:tid 456] [client 192.168.1.1:12345] ModSecurity: Warning. test. [file "/test.conf"] [line "1"] [id "123"] [msg "test"] [severity "CRITICAL"] [hostname "test"] [uri "/"] [unique_id "abc"]' | cscli explain --type modsecurity -f -

├ s01-parse
|   └ 🔴 crowdsecurity/modsecurity
└-------- parser failure 🔴

After fix

$ echo '[Mon Dec 15 05:34:22 2025] [security2:error] [pid 123:tid 456] [client 192.168.1.1:12345] ModSecurity: Warning. test. [file "/test.conf"] [line "1"] [id "123"] [msg "test"] [severity "CRITICAL"] [hostname "test"] [uri "/"] [unique_id "abc"]' | cscli explain --type modsecurity -f -

├ s01-parse
|   └ 🟢 crowdsecurity/modsecurity (+36 ~2)
├-------- parser success 🟢
├ Scenarios
    └ 🟢 crowdsecurity/modsecurity

Patch

Apply this patch to /etc/crowdsec/parsers/s01-parse/modsecurity.yaml:

# Fix 1: Move space inside optional [client IP] group
sed -i 's/(\\[client %{IPORHOST}\\])?/(\\[client %{IPORHOST}\\] )?/g' /etc/crowdsec/parsers/s01-parse/modsecurity.yaml

# Fix 2: Remove extra space between APACHEERRORPREFIX2 and ModSecurity
sed -i 's/%{APACHEERRORPREFIX2} ModSecurity:/%{APACHEERRORPREFIX2}ModSecurity:/g' /etc/crowdsec/parsers/s01-parse/modsecurity.yaml

# Reload CrowdSec
systemctl reload crowdsec

Additional Notes

Apache ErrorLogFormat

For CrowdSec compatibility, Apache's error log format should not include microseconds. The default Debian 13 format includes microseconds which the %{TIME} grok pattern cannot parse.

Recommended Apache configuration (/etc/apache2/conf-available/error-log-format.conf):

# CrowdSec compatibility: no microseconds
ErrorLogFormat "[%{%a %b %d %H:%M:%S %Y}t] [%-m:%l] [pid %P:tid %T] [client %{c}a] %M"

Enable with:

a2enconf error-log-format
systemctl reload apache2

Affected Versions

  • crowdsecurity/modsecurity v1.3 (current as of December 2025)

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions