Self-hosted WAF lab workflow with developer workstation, test domain, WAF node, upstream application, logs, latency evidence, and rollback path.
The lab routes a controlled request path through OWASP CRS and ModSecurity before it reaches a simple upstream application.
  • Developer workstation
  • Lab hostname
  • OWASP CRS + ModSecurity
  • NGINX reverse proxy
  • Upstream demo app
  • Evidence: HTTP status, rules, latency
  • Rollback route

Lab status

Product
OWASP CRS / ModSecurity / NGINX
Status
Completed smoke test
Updated
2026-07-09

Evidence policy

WAFWiki separates verified smoke-test results from architecture diagrams and methodology notes. A smoke test proves one narrow local path; it does not claim full production readiness.

Environment

Reproducibility notes

Host runtime

Docker Desktop 29.2.0 on macOS, aarch64

WAF image

owasp/modsecurity-crs:nginx

Image digest

sha256:5beec1cf50e9518821d11862b988809936b2abb43ed8a930a714130df39318ff

Connector

ModSecurity-nginx v1.0.4, libmodsecurity3 v3.0.16

Rule set

OWASP CRS 3.3.10, blocking paranoia level 1

Local ports

Upstream 127.0.0.1:18080, WAF 127.0.0.1:18081

Commands

How this lab can be reproduced

Start the upstream demo service

python3 -m http.server 18080 --bind 127.0.0.1
# In the published lab we used a tiny JSON handler instead of serving a directory.

The upstream responds locally before WAF routing is introduced.

Run OWASP CRS with ModSecurity and NGINX

docker run --rm -d --name wafwiki-crs-lab \
  -p 127.0.0.1:18081:8080 \
  -e BACKEND=http://host.docker.internal:18080 \
  -e MODSEC_RULE_ENGINE=on \
  -e BLOCKING_PARANOIA=1 \
  -e ANOMALY_INBOUND=5 \
  owasp/modsecurity-crs:nginx

The WAF container starts on localhost and proxies to the upstream demo service.

Compare clean and SQLi-like lab requests

curl -H 'Host: lab.wafwiki.local' http://127.0.0.1:18081/health
curl -H 'Host: lab.wafwiki.local' 'http://127.0.0.1:18081/search?id=1%20or%201%3D1'

The clean request returns 200. The SQLi-like lab request returns 403 with CRS rule evidence.

Observed result

What the hands-on test showed

Clean request

HTTP 200

GET /health reached the upstream JSON service through the WAF path.

SQLi-like lab request

HTTP 403

GET /search?id=1 or 1=1 was interrupted by the WAF.

Primary detection

Rule 942100

CRS logged SQL Injection Attack Detected via libinjection.

Blocking decision

Rule 949110

Inbound anomaly score reached the configured threshold of 5.

Clean request: http_code=200 total=0.009809
SQLi-like lab request: http_code=403 total=0.008503
ModSecurity-nginx v1.0.4 loaded 929 local rules.
libmodsecurity3 version 3.0.16 was reported at startup.
CRS message: SQL Injection Attack Detected via libinjection.
CRS blocking message: Inbound Anomaly Score Exceeded (Total Score: 5).

Evidence context

The original smoke-test evidence is preserved as a safe terminal capture.

The screenshot records the clean and SQLi-like HTTP outcomes, engine and connector versions, CRS detection message, and blocking rule without exposing unrelated local data.

Terminal-style screenshot of WAFWiki ModSecurity CRS Docker smoke-test evidence.

Limitations

What this result does not prove

Related research

Continue researching OWASP CRS / ModSecurity / NGINX