name: selfhostedops/crs-route-exclusions-by-rule # Episode 14: per route, remove only the CRS rules that fired on legitimate # requests there, not the blocking rule 949110 as in episode 13. The engine # stays on, virtual patching keeps working, and every CRS rule that did NOT # fire on a route still protects it (measured: SQLi on the git API stays 403). # # This file is what a human merged from an advisor issue on the demo box. The # rule ids are from OUR traffic. Do not copy them, generate your own: # curl -s -H "x-ops-token: $T" http://ops-readonly:8098/read/waf_blocked \ # | ops-readonly/waf-propose.py # Replace ops.example.com with your domain. SecLang needs the literal host. seclang_rules: # Forgejo REST API: issue text and file contents that look like attacks - | SecRule REQUEST_HEADERS:Host "@streq git.ops.example.com" "id:900201,phase:1,pass,nolog,chain,msg:'route exclusion 1'" SecRule REQUEST_URI "@beginsWith /api/v1/" "ctl:ruleRemoveById=930120,ctl:ruleRemoveById=932160,ctl:ruleRemoveById=932235,ctl:ruleRemoveById=941100,ctl:ruleRemoveById=941110,ctl:ruleRemoveById=941160,ctl:ruleRemoveById=941390" # git smart HTTP: 920420 is "content type not allowed", nothing about the payload. # One entry per repository. Use "@contains .git/git-" to cover all of them. - | SecRule REQUEST_HEADERS:Host "@streq git.ops.example.com" "id:900202,phase:1,pass,nolog,chain,msg:'route exclusion 2'" SecRule REQUEST_URI "@beginsWith /youruser/yourrepo.git/" "ctl:ruleRemoveById=920420" # Outline: documents with code blocks - | SecRule REQUEST_HEADERS:Host "@streq wiki.ops.example.com" "id:900203,phase:1,pass,nolog,chain,msg:'route exclusion 3'" SecRule REQUEST_URI "@beginsWith /api/documents.create" "ctl:ruleRemoveById=930100,ctl:ruleRemoveById=930110,ctl:ruleRemoveById=930120,ctl:ruleRemoveById=932160,ctl:ruleRemoveById=932230,ctl:ruleRemoveById=932235,ctl:ruleRemoveById=932260,ctl:ruleRemoveById=932370,ctl:ruleRemoveById=941100,ctl:ruleRemoveById=941110,ctl:ruleRemoveById=941160,ctl:ruleRemoveById=941180,ctl:ruleRemoveById=941390,ctl:ruleRemoveById=942100,ctl:ruleRemoveById=942190,ctl:ruleRemoveById=942350" # ntfy: message text with shell syntax - | SecRule REQUEST_HEADERS:Host "@streq ntfy.ops.example.com" "id:900204,phase:1,pass,nolog,chain,msg:'route exclusion 4'" SecRule REQUEST_URI "@beginsWith /yourtopic" "ctl:ruleRemoveById=932230" # n8n webhooks: JSON bodies with markup - | SecRule REQUEST_HEADERS:Host "@streq n8n.ops.example.com" "id:900205,phase:1,pass,nolog,chain,msg:'route exclusion 5'" SecRule REQUEST_URI "@beginsWith /webhook/" "ctl:ruleRemoveById=941100,ctl:ruleRemoveById=941110,ctl:ruleRemoveById=941160"