{
  "id": 4492746,
  "title": "A Practical Guide to ModSecurity/Coraza SecRule Syntax (and the mistakes that bite)",
  "url": "https://urgent.news/2026/08/30/a-practical-guide-to-modsecurity-coraza-secrule-syntax-and-the",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-08-30T19:40:10.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/whitmojm/a-practical-guide-to-modsecuritycoraza-secrule-syntax-and-the-mistakes-that-bite-m00"
  },
  "original_language": "en",
  "account": "Writing a custom SecRule for a WAF backed by ModSecurity or Coraza can be a powerful and well-designed task, but it does come with a steep learning curve. Most first-time custom rule writers either have no effect or unintentionally block traffic. This guide breaks down the anatomy of a rule and highlights specific mistakes that frequently trip people up.\n\nA SecRule consists of three key components: what to look at, how to match it, and what to do. The parts you'll frequently use include:\n- VARIABLE: REQUEST_URI, ARGS, REQUEST_HEADERS, REQUEST_COOKIES, REQUEST_METHOD, REMOTE_ADDR\n- @contains: for substring matching, @streq for exact match, @beginsWith / @endsWith, @rx for regex, @ipMatch for IP/CIDR, and built-in @detectSQLi / @detectXSS heuristics.\n\nEvery rule requires a unique ID, with phase:2 indicating that it checks after the request body is parsed. This is typically what you want when inspecting ARGS or REQUEST_BODY.\n\nMultiple SecRule lines chained together function as AND, meaning all conditions must match. The most common error is forgetting to add chain to non-final lines, resulting in two independent rules that don't match as intended.\n\nAllow-listing instead of blocking is another crucial aspect of writing WAF rules. Instead of disabling a rule globally when it makes a mistake, scope the exemption as narrowly as possible. For example:\nSecRule REQUEST_URI @beginsWith /editor/save id:1000003,phase:2,pass,nolog,ctl:ruleRemoveTargetById=941320;ARGS:content\nThis removes just one field from one rule's inspection, ensuring the rest of the request continues to be checked.\n\nRule ID collisions often occur when using the OWASP Core Rule Set (CRS), which has a reserved ID range of 900000–999999. Pick a custom rule ID above 1000000 to avoid silent collisions when CRS updates.",
  "summary": "If you run a WAF backed by ModSecurity or Coraza (the Go rewrite most modern setups use now — nginx, HAProxy via SPOE, Traefik plugins, etc.), sooner or later you write a custom SecRule by hand. The syntax is powerful and genuinely well-designed once it clicks, but the learning curve is real — most people's first custom rule either silently does nothing or blocks traffic they didn't mean to.…",
  "key_points": [],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 2,
    "also_reported_by": [
      {
        "outlet": "Dev.to",
        "title": "When to Index a Table: A Practical Guide for Analysts",
        "url": "https://urgent.news/2026/08/30/when-to-index-a-table-a-practical-guide-for-analysts",
        "published": "2026-08-30T13:00:29.000Z"
      }
    ]
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}