Integrate ModSecurity 3 with SOAR platforms for automated incident response and threat detection

Advanced 45 min Apr 29, 2026 66 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up ModSecurity 3 with structured logging, webhook notifications, and API integrations to automatically feed security events into SOAR platforms for real-time threat detection and incident response workflows.

Prerequisites

  • Root or sudo access
  • Web server (Nginx recommended)
  • Python 3.6 or later
  • SOAR platform with webhook support
  • Basic understanding of web application security

What this solves

ModSecurity 3 web application firewall generates security events that need structured processing for automated incident response. This tutorial configures ModSecurity with JSON logging, webhook notifications, and API integrations to feed security data into SOAR (Security Orchestration, Automation, and Response) platforms like Splunk Phantom, IBM Resilient, or Demisto for automated threat detection and response workflows.

Step-by-step installation and configuration

Update system packages and install dependencies

Start by updating your system and installing required packages for ModSecurity 3 compilation and web server integration.

sudo apt update && sudo apt upgrade -y
sudo apt install -y build-essential libcurl4-openssl-dev liblua5.3-dev libfuzzy-dev ssdeep gettext pkg-config libpcre3-dev libxml2-dev libcurl4-openssl-dev libyajl-dev doxygen nginx apache2-dev git autoconf automake libtool libgeoip-dev
sudo dnf update -y
sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y libcurl-devel lua-devel libfuzzy-devel ssdeep gettext-devel pkgconfig pcre-devel libxml2-devel yajl-devel doxygen nginx httpd-devel git autoconf automake libtool GeoIP-devel

Download and compile ModSecurity 3

Clone the ModSecurity 3 source code and compile it with all necessary modules for web application firewall functionality.

cd /opt
sudo git clone --depth 1 -b v3/master --single-branch https://github.com/SpiderLabs/ModSecurity.git
sudo chown -R $USER:$USER /opt/ModSecurity
cd ModSecurity
git submodule init
git submodule update
./build.sh
./configure
make
sudo make install

Install ModSecurity-nginx connector

Download and compile the ModSecurity-nginx connector to integrate ModSecurity 3 with Nginx web server.

cd /opt
sudo git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git
sudo chown -R $USER:$USER /opt/ModSecurity-nginx

Get nginx version for dynamic module compilation

nginx -v 2>&1 | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+'

Download nginx source matching your version (replace 1.24.0 with your version)

wget http://nginx.org/download/nginx-1.24.0.tar.gz tar zxvf nginx-1.24.0.tar.gz cd nginx-1.24.0

Configure and build the dynamic module

./configure --with-compat --add-dynamic-module=../ModSecurity-nginx make modules sudo cp objs/ngx_http_modsecurity_module.so /etc/nginx/modules/

Download OWASP Core Rule Set

Install the OWASP Core Rule Set (CRS) which provides comprehensive protection rules for common web application attacks.

cd /opt
sudo wget https://github.com/coreruleset/coreruleset/archive/v4.0.0.tar.gz
sudo tar -xzf v4.0.0.tar.gz
sudo mv coreruleset-4.0.0 /opt/coreruleset
sudo cp /opt/coreruleset/crs-setup.conf.example /opt/coreruleset/crs-setup.conf

Create ModSecurity main configuration

Configure ModSecurity 3 with JSON logging format for SOAR platform consumption and structured event data.

SecRuleEngine On
SecRequestBodyAccess On
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072
SecRequestBodyInMemoryLimit 131072
SecRequestBodyLimitAction Reject
SecRule REQUEST_HEADERS:Content-Type "text/xml" "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
SecRule REQUEST_HEADERS:Content-Type "application/xml" "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
SecRule REQUEST_HEADERS:Content-Type "text/xml" "id:'200002',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
SecResponseBodyAccess On
SecResponseBodyMimeType text/plain text/html text/xml
SecResponseBodyLimit 524288
SecResponseBodyLimitAction ProcessPartial
SecTmpDir /tmp/
SecDataDir /tmp/

JSON Logging Configuration for SOAR Integration

SecAuditEngine On SecAuditLogRelevantStatus "^(?:5|4(?!04))" SecAuditLogParts ABIJDEFHZ SecAuditLogType Serial SecAuditLog /var/log/modsecurity/audit.log SecAuditLogFormat JSON

Enhanced JSON logging with additional fields for SOAR

SecAuditLogStorageDir /var/log/modsecurity/ SecRule RESPONSE_STATUS "@streq 200" "id:999001,phase:5,pass,nolog,setvar:'tx.allowed_request=1'" SecRule TX:ALLOWED_REQUEST "@eq 1" "id:999002,phase:5,pass,log,msg:'Legitimate request logged for baseline',logdata:'client_ip=%{REMOTE_ADDR} user_agent=%{REQUEST_HEADERS.User-Agent} method=%{REQUEST_METHOD} uri=%{REQUEST_URI}'"

Custom action for webhook notifications

SecAction "id:999003,phase:1,pass,nolog,setvar:'tx.webhook_url=http://your-soar-platform.example.com/api/webhook/modsecurity'" SecDebugLog /var/log/modsecurity/debug.log SecDebugLogLevel 3 SecArgumentSeparator & SecCookieFormat 0 SecTmpSaveUploadedFiles on SecUploadDir /opt/modsecurity/var/upload

Create structured JSON logging script

Create a Python script to parse ModSecurity logs and format them for SOAR platform consumption with enriched metadata.

#!/usr/bin/env python3
import json
import re
import requests
import time
from datetime import datetime
import hashlib
import os
import sys

class ModSecuritySOARIntegration:
    def __init__(self, webhook_url, api_key=None):
        self.webhook_url = webhook_url
        self.api_key = api_key
        self.headers = {
            'Content-Type': 'application/json',
            'User-Agent': 'ModSecurity-SOAR-Integration/1.0'
        }
        if api_key:
            self.headers['Authorization'] = f'Bearer {api_key}'
    
    def parse_audit_log(self, log_line):
        """Parse ModSecurity audit log line and extract security event data"""
        try:
            log_data = json.loads(log_line)
            
            # Extract key security indicators
            event = {
                'timestamp': datetime.utcnow().isoformat() + 'Z',
                'source_ip': log_data.get('request', {}).get('remote_addr', ''),
                'request_method': log_data.get('request', {}).get('method', ''),
                'request_uri': log_data.get('request', {}).get('uri', ''),
                'user_agent': log_data.get('request', {}).get('headers', {}).get('User-Agent', ''),
                'host': log_data.get('request', {}).get('headers', {}).get('Host', ''),
                'response_status': log_data.get('response', {}).get('http_code', 0),
                'rules_matched': [],
                'threat_score': 0,
                'severity': 'info'
            }
            
            # Process matched rules
            messages = log_data.get('audit_data', {}).get('messages', [])
            for msg in messages:
                rule_info = {
                    'rule_id': msg.get('details', {}).get('ruleId', ''),
                    'message': msg.get('details', {}).get('msg', ''),
                    'data': msg.get('details', {}).get('data', ''),
                    'file': msg.get('details', {}).get('file', ''),
                    'line': msg.get('details', {}).get('lineNumber', ''),
                    'severity': msg.get('details', {}).get('severity', '')
                }
                event['rules_matched'].append(rule_info)
                
                # Calculate threat score based on rule severity
                severity_scores = {'EMERGENCY': 5, 'ALERT': 4, 'CRITICAL': 4, 'ERROR': 3, 'WARNING': 2, 'NOTICE': 1}
                event['threat_score'] += severity_scores.get(rule_info['severity'].upper(), 1)
            
            # Set overall severity based on threat score
            if event['threat_score'] >= 10:
                event['severity'] = 'critical'
            elif event['threat_score'] >= 5:
                event['severity'] = 'high'
            elif event['threat_score'] >= 3:
                event['severity'] = 'medium'
            else:
                event['severity'] = 'low'
            
            # Generate unique event ID
            event_string = f"{event['timestamp']}{event['source_ip']}{event['request_uri']}"
            event['event_id'] = hashlib.sha256(event_string.encode()).hexdigest()[:16]
            
            return event
            
        except (json.JSONDecodeError, KeyError) as e:
            print(f"Error parsing log line: {e}")
            return None
    
    def send_to_soar(self, event_data):
        """Send security event to SOAR platform via webhook"""
        try:
            # Prepare SOAR-compatible payload
            soar_payload = {
                'alert_type': 'modsecurity_waf',
                'severity': event_data['severity'],
                'timestamp': event_data['timestamp'],
                'source': 'ModSecurity WAF',
                'event_id': event_data['event_id'],
                'indicators': {
                    'ip_address': event_data['source_ip'],
                    'user_agent': event_data['user_agent'],
                    'host': event_data['host'],
                    'request_uri': event_data['request_uri']
                },
                'details': {
                    'method': event_data['request_method'],
                    'response_code': event_data['response_status'],
                    'threat_score': event_data['threat_score'],
                    'matched_rules': event_data['rules_matched']
                },
                'raw_data': event_data
            }
            
            response = requests.post(
                self.webhook_url,
                headers=self.headers,
                json=soar_payload,
                timeout=10
            )
            
            if response.status_code == 200:
                print(f"Successfully sent event {event_data['event_id']} to SOAR platform")
                return True
            else:
                print(f"Failed to send event to SOAR: HTTP {response.status_code}")
                return False
                
        except requests.RequestException as e:
            print(f"Error sending to SOAR platform: {e}")
            return False

def monitor_audit_log(log_file_path, soar_integration):
    """Monitor ModSecurity audit log and send events to SOAR"""
    try:
        with open(log_file_path, 'r') as f:
            # Seek to end of file
            f.seek(0, 2)
            
            while True:
                line = f.readline()
                if line:
                    event = soar_integration.parse_audit_log(line.strip())
                    if event and event['threat_score'] > 0:
                        soar_integration.send_to_soar(event)
                else:
                    time.sleep(1)
                    
    except FileNotFoundError:
        print(f"Audit log file not found: {log_file_path}")
    except KeyboardInterrupt:
        print("Monitoring stopped")

if __name__ == "__main__":
    # Configuration - modify these values for your SOAR platform
    WEBHOOK_URL = os.getenv('MODSEC_SOAR_WEBHOOK', 'http://your-soar-platform.example.com/api/webhook/modsecurity')
    API_KEY = os.getenv('MODSEC_SOAR_API_KEY', '')
    LOG_FILE = '/var/log/modsecurity/audit.log'
    
    soar = ModSecuritySOARIntegration(WEBHOOK_URL, API_KEY)
    monitor_audit_log(LOG_FILE, soar)

Configure Nginx with ModSecurity module

Enable ModSecurity module in Nginx and configure it to use our security rules and logging settings.

# Add at the top of nginx.conf
load_module modules/ngx_http_modsecurity_module.so;

http {
    # ModSecurity configuration
    modsecurity on;
    modsecurity_rules_file /opt/ModSecurity/modsecurity.conf;
    
    # Enable detailed logging
    log_format modsec_json escape=json '{'
        '"time":"$time_iso8601",'
        '"remote_addr":"$remote_addr",'
        '"request":"$request",'
        '"status":$status,'
        '"body_bytes_sent":$body_bytes_sent,'
        '"http_referer":"$http_referer",'
        '"http_user_agent":"$http_user_agent",'
        '"request_time":$request_time,'
        '"upstream_response_time":"$upstream_response_time"'
    '}';
    
    access_log /var/log/nginx/access.log modsec_json;
    error_log /var/log/nginx/error.log warn;
    
    # Include other configurations
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Create virtual host with ModSecurity protection

Configure a virtual host that demonstrates ModSecurity protection with OWASP Core Rule Set integration.

server {
    listen 80;
    server_name example.com www.example.com;
    
    # Enable ModSecurity for this virtual host
    modsecurity on;
    modsecurity_rules_file /opt/ModSecurity/modsecurity.conf;
    
    # Include OWASP Core Rule Set
    modsecurity_rules '
        Include /opt/coreruleset/crs-setup.conf
        Include /opt/coreruleset/rules/*.conf
        
        # Custom rule for SOAR integration
        SecRule REQUEST_URI "@detectSQLi" \
            "id:2001,phase:2,block,msg:SQL Injection Attack,logdata:Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME},tag:attack-sqli,severity:CRITICAL"
        
        SecRule ARGS "@detectXSS" \
            "id:2002,phase:2,block,msg:XSS Attack,logdata:Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME},tag:attack-xss,severity:CRITICAL"
        
        # Custom action to trigger webhook on high severity events
        SecRule TX:ANOMALY_SCORE "@gt 4" \
            "id:2003,phase:5,pass,exec:/opt/modsecurity/webhook_notify.sh %{TX.ANOMALY_SCORE} %{REMOTE_ADDR} %{REQUEST_URI}"
    ';
    
    location / {
        root /var/www/html;
        index index.html index.htm;
        
        # Additional security headers
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header X-Content-Type-Options "nosniff" always;
    }
    
    # Specific protection for admin areas
    location /admin {
        modsecurity_rules '
            SecRuleRemoveById 920350
            SecRule REQUEST_URI "@beginsWith /admin" \
                "id:3001,phase:1,pass,log,msg:Admin area access,logdata:IP: %{REMOTE_ADDR} URI: %{REQUEST_URI}"
        ';
        
        root /var/www/html;
        index index.html;
    }
}

Create webhook notification script

Create a shell script that triggers immediate webhook notifications for high-severity security events.

#!/bin/bash

ModSecurity Webhook Notification Script

Arguments: $1=anomaly_score $2=remote_addr $3=request_uri

ANOMALY_SCORE=$1 REMOTE_ADDR=$2 REQUEST_URI=$3 TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ") WEBHOOK_URL="${MODSEC_SOAR_WEBHOOK:-http://your-soar-platform.example.com/api/webhook/modsecurity}" API_KEY="${MODSEC_SOAR_API_KEY:-}"

Create JSON payload for immediate notification

PAYLOAD=$(cat <Send webhook with proper headers if [ -n "$API_KEY" ]; then curl -X POST "$WEBHOOK_URL" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $API_KEY" \ -d "$PAYLOAD" \ --max-time 5 \ --silent \ --output /dev/null else curl -X POST "$WEBHOOK_URL" \ -H "Content-Type: application/json" \ -d "$PAYLOAD" \ --max-time 5 \ --silent \ --output /dev/null fi

Log the notification attempt

echo "[$(date)] Webhook sent for IP: $REMOTE_ADDR, URI: $REQUEST_URI, Score: $ANOMALY_SCORE" >> /var/log/modsecurity/webhook.log

Set up log directories and permissions

Create necessary directories and set appropriate permissions for ModSecurity logging and scripts.

sudo mkdir -p /var/log/modsecurity
sudo mkdir -p /opt/modsecurity/var/upload
sudo chown -R www-data:www-data /var/log/modsecurity
sudo chown -R www-data:www-data /opt/modsecurity/var/upload
sudo chmod 755 /opt/modsecurity/webhook_notify.sh
sudo chmod 755 /opt/modsecurity/soar_integration.py

Create logrotate configuration

sudo tee /etc/logrotate.d/modsecurity > /dev/null <

Configure environment variables for SOAR integration

Set up environment variables for SOAR platform connection details and API credentials.

# ModSecurity SOAR Integration Configuration
MODSEC_SOAR_WEBHOOK=https://your-soar-platform.example.com/api/webhook/modsecurity
MODSEC_SOAR_API_KEY=your_api_key_here
MODSEC_THREAT_THRESHOLD=3

Create systemd service for SOAR integration

Create a systemd service to run the SOAR integration script continuously and ensure it starts on boot.

[Unit]
Description=ModSecurity SOAR Integration Service
After=network.target nginx.service
Requires=nginx.service

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/opt/modsecurity
ExecStart=/usr/bin/python3 /opt/modsecurity/soar_integration.py
Restart=always
RestartSec=5
EnvironmentFile=/etc/environment

Logging

StandardOutput=journal StandardError=journal SyslogIdentifier=modsecurity-soar

Security settings

NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ProtectHome=true ReadWritePaths=/var/log/modsecurity [Install] WantedBy=multi-user.target

Enable and start services

Enable the Nginx virtual host, start ModSecurity protection, and activate the SOAR integration service.

# Enable the protected site
sudo ln -s /etc/nginx/sites-available/protected-site /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Enable and start the SOAR integration service

sudo systemctl daemon-reload sudo systemctl enable modsecurity-soar sudo systemctl start modsecurity-soar

Check service status

sudo systemctl status modsecurity-soar sudo systemctl status nginx

Configure SOAR platform webhook endpoints

Set up SOAR platform webhook receiver

Configure your SOAR platform to receive and process ModSecurity security events. This example shows configuration for a generic SOAR platform.

# Example webhook endpoint configuration for SOAR platforms

Endpoint: POST /api/webhook/modsecurity

Required headers:

Content-Type: application/json

Authorization: Bearer YOUR_API_KEY (optional)

Expected payload structure:

{ "alert_type": "modsecurity_waf|modsecurity_high_severity", "severity": "low|medium|high|critical", "timestamp": "2024-01-15T10:30:00Z", "source": "ModSecurity WAF", "event_id": "unique_event_identifier", "indicators": { "ip_address": "203.0.113.10", "user_agent": "Mozilla/5.0...", "host": "example.com", "request_uri": "/vulnerable-endpoint" }, "details": { "method": "POST", "response_code": 403, "threat_score": 8, "matched_rules": [ { "rule_id": "942100", "message": "SQL Injection Attack Detected", "severity": "CRITICAL", "data": "SELECT * FROM users" } ] } }

Configure automated response workflows

Set up automated incident response workflows in your SOAR platform based on ModSecurity event data.

# Example SOAR workflow configuration

Trigger: ModSecurity webhook with severity >= "high"

Workflow steps:

  1. Parse incoming ModSecurity event
  2. Enrich with threat intelligence data
  3. Check IP reputation (VirusTotal, AbuseIPDB)
  4. Create incident ticket
  5. If threat_score > 8:
- Add IP to firewall blocklist - Send alert to security team - Create SIEM correlation rule
  1. If repeated attacks from same IP:
- Implement rate limiting - Escalate to senior analyst
  1. Update threat intelligence database
  2. Generate incident response report

Auto-remediation rules:

  • SQL Injection attempts: Block IP for 24 hours
  • XSS attempts: Rate limit and monitor
  • Path traversal: Block immediately
  • Anomaly score > 10: Immediate escalation

Testing and validation

Test SQL injection detection

Verify that ModSecurity detects SQL injection attempts and sends alerts to your SOAR platform.

# Test SQL injection detection
curl -X POST "http://example.com/search" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "query='; DROP TABLE users; --"

Test XSS detection

curl "http://example.com/search?q="

Test path traversal

curl "http://example.com/file?path=../../../etc/passwd"

Check ModSecurity audit log

sudo tail -f /var/log/modsecurity/audit.log

Check webhook notifications

sudo tail -f /var/log/modsecurity/webhook.log

Check SOAR integration service logs

sudo journalctl -u modsecurity-soar -f

Verify your setup

# Check ModSecurity module is loaded
nginx -V 2>&1 | grep -o with-http_modsecurity_module

Verify SOAR integration service

sudo systemctl status modsecurity-soar

Check log files are being created

ls -la /var/log/modsecurity/

Test webhook connectivity

curl -X POST "$MODSEC_SOAR_WEBHOOK" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $MODSEC_SOAR_API_KEY" \ -d '{"test": "connectivity"}'

Verify OWASP rules are active

sudo grep -r "Include.*coreruleset" /etc/nginx/

Check for recent security events

sudo tail -20 /var/log/modsecurity/audit.log | grep -o '"msg":"[^"]*"'

Common issues

SymptomCauseFix
Nginx fails to start with ModSecurity moduleModule path incorrect or missing dependenciesCheck /etc/nginx/modules/ and run ldd ngx_http_modsecurity_module.so
SOAR webhooks not being sentNetwork connectivity or API key issuesTest webhook URL manually with curl and verify API key
High false positive rateOWASP rules too strict for applicationTune rules in /opt/coreruleset/crs-setup.conf and whitelist legitimate traffic
ModSecurity logs not in JSON formatAudit log format not set correctlyVerify SecAuditLogFormat JSON in modsecurity.conf
SOAR integration service crashesPython dependencies or file permissionsCheck service logs with journalctl -u modsecurity-soar and fix file ownership
Performance impact on web serverModSecurity processing overheadTune SecRequestBodyLimit and disable unnecessary rule sets

Performance optimization and fine-tuning

Optimize ModSecurity performance

Configure ModSecurity for high-performance environments with reduced latency and resource usage.

# Performance optimization settings
SecRequestBodyLimit 1048576
SecRequestBodyInMemoryLimit 131072
SecResponseBodyLimit 524288

Reduce logging overhead for high-traffic sites

SecAuditLogRelevantStatus "^(?:5|4(?!04))" SecAuditEngine RelevantOnly

Optimize rule processing

SecRuleEngine On SecRequestBodyAccess On SecResponseBodyAccess Off

Cache compiled rules

SecDataDir /opt/modsecurity/var/cache SecTmpDir /tmp/modsecurity

Sampling for high-volume sites (log 1 in 100 requests)

SecRule REQUEST_HEADERS:User-Agent "@rx .*" \ "id:9001,phase:1,pass,nolog,skipAfter:END_SAMPLING,ctl:auditEngine=Off" SecRule TX:SAMPLING_RND "@lt 1" \ "id:9002,phase:1,pass,nolog,ctl:auditEngine=On" SecMarker "END_SAMPLING"

Next steps

Running this in production?

Want this handled for you? Running ModSecurity at scale adds capacity planning, rule tuning, false positive management, and 24/7 threat response. See how we run infrastructure like this for European SaaS and e-commerce teams.

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle infrastructure security hardening for businesses that depend on uptime. From initial setup to ongoing operations.