Skip to content
Switch branches/tags


Failed to load latest commit information.
Latest commit message
Commit time


The ModSecurity-Envoy is Envoy version compiled with HTTP filter (can be opt-in/out) running ModSecurity (V3). In other words you can run and configure WAF (ModSecurity) rules on HTTP Traffic that flows through envoy.

The most common use case is for ModSecurity-Envoy is to apply WAF on East-West traffic inside kubernetes deployments. As Envoy is the de-facto standard proxy in kubernetes deployments and is usually deployed in every pod you can deploy this Envoy version and Enable ModSecurity-Envoy Filter on all pods or on the most important ones.

Some of the ideas behind the project are described in this blog



ModSecurity-Envoy depends on Envoy (as a git submodule) and ModSecurity (a sibling directory). The modsecurity directory contains two symbolic links to the sibling directory.

git clone
git clone

cd ModSecurity-envoy
git submodule update --init

The directory structure should be as follows:

+-- ModSecurity-envoy
|  +-- modsecurity
|  |  +-- include -> ../../ModSecurity/headers
|  |  +-- libmodsecurity.a -> ../../ModSecurity/src/.libs/libmodsecurity.a
+-- ModSecurity

For more details on how to compile ModSecurity read ModSecurity's documentation.

Compiling on host

You can compile ModSecurity-Envoy on host, the same as you would compile Envoy. However, you will need these additional dependencies:

sudo apt-get install -y libtool cmake realpath clang-format-5.0 automake 
sudo apt-get install -y g++ flex bison curl doxygen libyajl-dev libgeoip-dev libtool dh-autoreconf libcurl4-gnutls-dev libxml2 libpcre++-dev libxml2-dev

To build run

bazel build //:envoy

For more information on envoy's building system read Envoy's documentation.

Using the docker images

You can build docker images for envoy-build and envoy See ci/


ModSecurity-Envoy Filter accept the configuration defined in http_filter.proto

You will need to modify the Envoy config file to add the filter to the filter chain for a particular HTTP route configuration. See the examples in conf.

Note: By adding metadata to specific routes, you can have granular control to disable the filter:

      # To only disable requests / responses processing
      # disable_request: true
      # disable_response: true
      # Or, as a shorthand, use disable to disable both
      disable: true

The configuration for the filter is provided under the http_filters:

        # before envoy.router because order matters!
        - name: envoy.filters.http.modsecurity
            # ModSecurity rules can either be provided by a path
            rules_path: /etc/modsecurity.conf
            # Additionally you can provide inline rules (will be loaded after processing the rules_path, if provided)
            rules_inline: |
              # ModSecurity rules
              # ...
            # Optionally, you can provide a webhook configuration
              # The http_uri field is mandatory
                uri: http://localhost:10000/wh_callback
                cluster: service2
                  seconds: 3
              # Optionally you can provide a secret to sign the webhooks with an HMAC-256 (for more information see the .proto file)
              secret: webhook_secret
        - name: envoy.router
          config: {}

OWASP ModSecurity Core Rule Set (CRS)

CRS is a set of generic attack detection rules for use with ModSecurity and aims to protect web applications from wide range of attacks. For more information check out

Download and extract the latest rules to the directory.

tar xvzf v3.1.1.tar.gz

The configuration examples include the relevant OWASP rules. See ./conf/modsecurity.conf and ./conf/lds.yaml for usage example.



How it works

First let's run an echo server that we will use as our upstream

docker run -p 5555:80 kennethreitz/httpbin

Now let's run the envoy

sudo ./bazel-bin/envoy-static -c conf/envoy-modsecurity-example-lds.yaml -l info

Make our first request

curl -X GET "" -H "accept: application/json"

Let's download Nikto which is the most popular Open Source web server scanner

perl nikto-master/program/ -h localhost:5555

Now we can cat /var/log/modsec_audit.log and see all detected attacks which in production can be piped to a SIEM of your choice or any other centralized log.

Let's try and add our own RULE as each WAF are designed to be configurable to protect different web applications.

Make sure the following line is in modsecurity-example.conf or in the configuration under rules_inline.

SecRule ARGS:param1 "test" "id:1,deny,msg:'this',msg:'is',msg:'a',msg:'test'"

This line will detect any url with argument ?param1=test param.

reload Envoy's configuration and execute the following command curl -X GET "" -H "accept: application/json"

check the logs via tail -f and you will see the following output

ModSecurity: Warning. Matched "Operator `Rx' with parameter `test' against variable `ARGS:param1' (Value: `test' ) [file "crs-setup.conf"] [line "7"] [id "1"] [rev ""] [msg "test"] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname ""] [uri "/"] [unique_id "152991475598.002681"] [ref "o0,4v13,4"]

If we have a webhook installed, triggering a rule will result in a similar request:

POST /wh_callback
host: localhost:10000
content-type: application/json
content-length: 530
x-envoy-webhook-signature-type: HMAC-SHA256
x-envoy-webhook-signature-value: d7c224c82cee677e32dc3ae0d2e60fae5a0c9714613b55bd0791fd226d8f22e7
x-envoy-internal: true
x-envoy-expected-rq-timeout-ms: 3000

{"accuracy": 0, "clientIpAddress": "", "data": "", "id": "156690498720.063187", "isDisruptive": false, "match": "Matched \"Operator `Rx' with parameter `test' against variable `ARGS:param1' (Value: `test' )", "maturity": 0, "message": "Test rule", "noAuditLog": false, "phase": 1, "reference": "o0,4v13,4", "rev": "", "ruleFile": "<<reference missing or not informed>>", "ruleId": 1, "ruleLine": 6, "saveMessage": true, "serverIpAddress": "", "severity": 0, "uriNoQueryStringDecoded": "/", "ver": "", "tags": []}