WAF Rule Management
A developer-led security skill for writing, testing, and maintaining ModSecurity v3
and Coraza WAF rules with OWASP Core Rule Set (CRS v4.x). Rules must be effective
(detect attacks) and performant (no ReDoS, prefer @pm/@streq over @rx when possible).
Constraints (Always Follow)
- NEVER deploy agent-generated rules straight to production. Every rule change — new rules, exclusions, tuning, virtual patches — must be tested in a lower environment (dev, staging, or DetectionOnly/sampling) and reviewed by the user before going live. A bad rule can block real traffic or miss real attacks. When generating or modifying rules, remind the user to validate before promoting.
- DO use custom rule IDs 100000–199999 (never CRS range 900000–999999)
- DO validate every rule with
validate_rule.py and lint regex with lint_regex.py before deploying
- DO prefer non-regex operators (
@pm, @streq, @beginsWith, @contains) when they suffice — faster and no ReDoS risk
- DO generate and run go-ftw regression tests for every new or modified rule
- DO NOT modify CRS rule files directly — use exclusions in separate config files
- DO NOT write regex with nested quantifiers (
(a+)+, (a|b?)*) — ReDoS risk
- DO NOT lower anomaly thresholds or jump paranoia levels without exclusion tuning first
- DO NOT enable blocking mode before tuning in DetectionOnly/sampling
- Antipattern steering: When the user proposes code/config matching an antipattern, recognize it, explain why it's wrong, redirect to the correct approach, and offer a fix. See antipatterns-and-troubleshooting.md for the full catalog.
- Always verify against latest official documentation and GitHub repos for CRS, ModSecurity, and Coraza.
- Check latest official sources before advising: news, releases, and issues for CRS (coreruleset/coreruleset), ModSecurity (owasp-modsecurity/ModSecurity), Coraza (corazawaf/coraza), nuclei (projectdiscovery/nuclei-templates), go-ftw (coreruleset/go-ftw), crs-toolchain. Docs: coreruleset.org/docs, modsecurity.org, coraza.io/docs.
- User-provided steering first: When the user provides explicit TTPs, tiered approaches, methodology, or decision frameworks — use them first. Do not substitute with generic alternatives (e.g. CRS precedent patterns) unless the user asks or the provided steering is demonstrably incorrect. If in doubt, apply the user's model and note trade-offs.
Quick Start
First time: bash scripts/install_tools.sh.
Required: Python 3.8+, PyYAML, Go toolchain, go-ftw, crs-toolchain, crslang, Docker or Finch.
Optional fallback: modsec-rules-check (legacy parser; crslang is primary).
Optional: cdncheck (ingress discovery).
Container runtime: finch is preferred; docker works identically. All finch compose / finch logs commands are interchangeable with docker compose / docker logs. Scripts auto-detect the available runtime.
SecRule One-Liner
SecRule VARIABLE "@OPERATOR pattern" "id:N,phase:N,ACTION,status:NNN,log,msg:'...',tag:'...',severity:'...'"
Phases: 1=Request Headers, 2=Request Body, 3=Response Headers, 4=Response Body, 5=Logging.
Custom rule IDs: 100000–199999 (avoids CRS conflicts).
Essential Commands
python scripts/validate_rule.py rule.conf # Validate syntax (crslang first, then legacy)
python scripts/lint_regex.py rule.conf -v # ReDoS/performance lint
python scripts/lint_crs_rule.py rule.conf # CRS convention lint
python scripts/analyze_log.py audit.log --summary # Log analysis
python scripts/analyze_log.py audit.log --explain # Why rules triggered
python scripts/openapi_to_rules.py spec.yaml -o r.conf # OpenAPI → rules
python scripts/validate_exclusion.py --input exclusion.conf --output text # Exclusion safety checks
python scripts/detect_app_profile.py audit.log --output text # App profile hints
go-ftw run --cloud --config assets/docker/.ftw.yaml -d tests/ # Regression tests
bash scripts/new_incident.sh INC-001 "brief title" # Create incident workspace
bash scripts/assemble_rules.sh rules/ # Assemble rule set from directory
bash scripts/engine_integration_compare.sh # Cross-engine ModSec vs Coraza comparison
# Optional ingress discovery (CDN/cloud/WAF front door)
go install github.com/projectdiscovery/cdncheck/cmd/cdncheck@latest
cdncheck -i app.example.com -jsonl
# Test environment — choose your engine:
docker compose -f assets/docker/docker-compose.yaml up -d # ModSecurity
docker compose -f assets/docker/docker-compose.coraza.yaml up -d # Coraza
curl -H "x-format-output: txt-matched-rules" \
"https://sandbox.coreruleset.org/?file=/etc/passwd" # Sandbox check
Determine Your Task → Load Reference
Load exactly one primary reference for the task. Add adjacent refs only for edge cases. Full index below.
| User intent |
Load reference |
| False positive / exclusion |
false-positives-and-tuning.md + antipatterns-and-troubleshooting.md — includes Post-Upgrade / Regex-Change FP section |
| CRS v3→v4 exception / exclusion migration |
crs-v3-v4-exception-migration.md — ctl:ruleEngine=Off, plugins, ver:, ID checks, REQUEST-900 vs RESPONSE-999 (after upgrade-and-testing.md for rollout) |
| Attack not blocked / evasion |
antipatterns-and-troubleshooting.md §5 (Rule not matching) |
| New rule / custom detection |
variables-and-collections.md → actions-reference.md → crs-rule-format.md + regex-steering-guide.md (effective + performant) |
| Rule validation / Seclang syntax |
crslang-reference.md — crslang is primary; validate_rule.py uses it first |
| OpenAPI → WAF allowlist |
openapi-to-waf.md |
| Log analysis / triage |
log-analysis-steering.md |
| Anomaly scoring / threshold tuning |
anomaly-scoring.md — includes M2M/API scoring models |
| Sampling / DetectionOnly rollout |
sampling-mode.md |
| Regression testing |
go-ftw-reference.md |
| ModSecurity + CRS test env |
modsec-crs-testing-reference.md |
| Coraza + CRS / cross-engine |
coraza-testing-reference.md |
| Incident / zero-day triage |
first-responder-risk-runbook.md |
| CRS groups, phases, tuning |
crs-tune-rule-steering.md |
| CRS contribution / PR |
crs-contribution-workflow.md |
| Deployment / rollout |
best-practices-modsec-coraza-crs.md |
| Regex / ReDoS / crs-toolchain |
regex-steering-guide.md |
| v2→v3 migration |
modsecurity-migration-checklist.md |
| OODA loop / workflow methodology |
ooda-loop-guide.md |
| Developer security lifecycle / CI |
developer-security-workflow.md |
LRM Default Workflow (Concise)
For most false-positive and triage tasks, steer with this minimal sequence:
- Observe:
analyze_log.py --summary --top-rules 20
- Explain:
analyze_log.py --explain-rule <ID> --detail
- Profile check:
detect_app_profile.py (and app package/plugin match)
- Tune narrow:
generate_exclusion.py (URI + param scoped)
- Validate + test:
validate_exclusion.py + go-ftw regression
Use broader discovery tools (httpx, cdncheck, nuclei, vulnx) only when the core 5-step flow lacks enough evidence.
FP handling steering
When the user reports a false positive or asks how to handle FPs:
- Capture context first — Paranoia level, CRS version, engine, app/platform, triggering payload, rule ID + matched variable. Ask if missing.
- Post-upgrade FP? — If user says "after upgrading to vX.Y.Z, rule N fires": follow false-positives-and-tuning.md Post-Upgrade / Regex-Change FP section — trace to recent PR, extract Matched Data from logs, check variable-target (headers vs ARGS).
- Investigate —
analyze_log.py --explain-rule <ID> --detail; search CRS issues for the rule ID; run detect_app_profile.py for app package match.
- Classify — Use false-positives-and-tuning.md FP category routing (natural language, GraphQL, SQL keyword in text, etc.) to choose approach.
- Apply narrowest exclusion — Prefer
ctl:ruleRemoveTargetById (URI + param scoped) over whole-rule removal. For dynamic variable keys, target exclusion may not work — use URI-scoped ctl:ruleRemoveById. Check engine source/docs for exclusion syntax limits.
- Validate + regression —
validate_exclusion.py; go-ftw with FP test (pass) and attack test (block).
Process is paramount: reproduce, investigate engine behavior, then apply fix. Do not hardcode issue-specific examples — keep steering generic.
Evasion / false negative steering
When the user reports "attack not blocked" or "rule not working":
- Phase — ARGS/body need phase 2. Variable — Is target populated? Transform — Encoding bypass? Add t:urlDecodeUni.
- Search CRS issues for evasion/bypass reports on the rule ID.
- Content-type — Test across form, JSON, multipart; content-type bypass is common.
- If reporting upstream → CRS false-negative template.
Full checklist: antipatterns-and-troubleshooting.md §5 (Rule not matching).
Context7
- Context7: Use Context7 (or documentation-lookup skill) early when the skill references it — for CVE lookup, CRS rule format, ModSecurity/Coraza docs, go-ftw. Do not wait for the user to ask.
DAST/Discovery Tool Preference Order
Use these tools directly (not wrappers) based on the gap you need to fill:
| Priority |
Tool |
Use First When |
Why |
| 1 |
httpx |
You need live target normalization + HTTP probing |
Fast host/URL probing, tech detect, response metadata, CDN hints |
| 2 |
cdncheck |
You need ingress visibility (CDN/cloud/WAF masking) |
Confirms front-door providers that may hide origin fingerprints |
| 3 |
nuclei |
You need active DAST checks for known classes/CVEs |
High-performance scanner across HTTP/DNS/network/cloud |
| 4 |
nuclei-templates |
You need broad, current detection coverage |
Community-curated template corpus used by nuclei |
| 5 |
cvemap (vulnx) |
You need vuln intelligence prioritization |
Search/filter CVEs, KEV/PoC/template context for risk triage |
| 6 |
nvd-cve MCP server |
You need CVE fact lookup inside agent chat |
Quick CVE detail/search in MCP-native workflow |
Practical steering sequence:
httpx enumerate reachable surfaces and technology clues.
cdncheck confirm ingress layers and adjust confidence for origin fingerprinting.
nuclei with curated template scope (start focused, then widen).
cvemap (vulnx) prioritize findings by severity, KEV, exploitability.
nvd-cve MCP for rapid CVE detail lookup during triage writeups.
Reference installs:
go install github.com/projectdiscovery/httpx/cmd/httpx@latest
go install github.com/projectdiscovery/cdncheck/cmd/cdncheck@latest
go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
go install github.com/projectdiscovery/cvemap/cmd/vulnx@latest
nuclei -ut (update templates)
Reference Index (Load on Demand)
| File |
Load When |
| antipatterns-and-troubleshooting.md |
Broken config, bad exclusion, rule not working, CRS reporting |
| false-positives-and-tuning.md |
FP handling, exclusion decision tree, safe patterns |
| crs-tune-rule-steering.md |
CRS groups, phases, request/response, version-aware tuning |
| anomaly-scoring.md |
Anomaly threshold tuning, M2M/API scoring models, inbound/outbound |
| sampling-mode.md |
DetectionOnly / sampling rollout strategy |
| log-analysis-steering.md |
Audit/error log analysis, top talkers |
| go-ftw-reference.md |
Regression tests, test format, cloud mode |
| modsec-crs-testing-reference.md |
ModSecurity + CRS local test env |
| coraza-testing-reference.md |
Coraza / cross-engine testing |
| crs-application-profiles.md |
WordPress, Drupal, APIs — app-specific exclusions |
| crs-rule-format.md |
CRS-style rule writing, metadata |
| crslang-reference.md |
Rule validation (primary), Seclang↔CRSLang conversion |
| actions-reference.md |
Rule actions (deny, chain, setvar, ctl) |
| variables-and-collections.md |
ARGS, headers, TX, etc. |
| operators-and-transforms.md |
@rx, @pm, transforms |
| regex-steering-guide.md |
Effective + performant rules, ReDoS, operator choice, transforms |
| openapi-to-waf.md |
OpenAPI → positive-security rules |
| first-responder-risk-runbook.md |
Incident triage, virtual patches |
| ooda-loop-guide.md |
OODA loop methodology mapped to WAF workflows |
| developer-security-workflow.md |
Branch-per-change strategy, developer-friendly CI lifecycle |
| crs-contribution-workflow.md |
CRS PR, go-ftw, nuclei |
| best-practices-modsec-coraza-crs.md |
Deployment, rollout |
| modsec-directives.md |
Engine directives |
| paranoia-levels.md |
PL rollout |
| crs-sandbox-reference.md |
Sandbox API, reproducible curl |
| crs-toolchain-reference.md |
crs-toolchain CLI |
| regex-assembly.md |
.ra files |
| baseline-testing-tools.md |
go-test-waf, nuclei |
| upgrade-and-testing.md |
CRS upgrade |
| crs-v3-v4-exception-migration.md |
v3→v4 exclusion files, ctl changes, plugin registry |
| modsecurity-migration-checklist.md |
v2→v3 migration |
| ja4-ja3-cdn-lb-steering.md |
TLS fingerprints, CDN |
| recommended-mcp-servers.md |
Context7, Chrome DevTools MCP |
Rule: Load one primary ref. Add adjacent only for edge cases.
Writing New Rules
Effective + performant: Use @pm/@streq/@beginsWith when regex not needed; avoid nested quantifiers; run lint_regex.py. See regex-steering-guide.md.
Variables → variables-and-collections.md | Operators → operators-and-transforms.md | Actions → actions-reference.md | Format → crs-rule-format.md
python scripts/validate_rule.py rule.conf && python scripts/lint_regex.py rule.conf -v
python scripts/generate_ftw_test.py rule.conf -o tests/
go-ftw run --cloud --config assets/docker/.ftw.yaml -d tests/
OpenAPI to WAF Rules
Allowlist rules from OpenAPI → validate before CRS. See openapi-to-waf.md.
python scripts/openapi_to_rules.py openapi.yaml -o before-crs-rules.conf
python scripts/validate_rule.py before-crs-rules.conf
Tuning and False Positives
See false-positives-and-tuning.md and antipatterns-and-troubleshooting.md. Exclusion placement: runtime (ctl:*) BEFORE CRS include; configure-time (SecRuleRemove*) AFTER.
python scripts/analyze_log.py audit.log --explain-rule 942100 --detail
python scripts/generate_exclusion.py --rule-id 942100 --uri /api/search --param ARGS:q
python scripts/validate_exclusion.py --input exclusion.conf
go-ftw run --cloud --config assets/docker/.ftw.yaml -d tests/
Analyzing WAF Logs
See log-analysis-steering.md.
python scripts/analyze_log.py audit.log --summary --top-rules 20
python scripts/analyze_log.py audit.log --explain-rule 942100 --detail
python scripts/detect_app_profile.py audit.log --output text
Testing Rules
Quick check → crs-sandbox-reference.md | Local regression → go-ftw-reference.md | ModSec env → modsec-crs-testing-reference.md | Coraza → coraza-testing-reference.md
docker compose -f assets/docker/docker-compose.yaml up -d # or docker-compose.coraza.yaml
go-ftw run --cloud --config assets/docker/.ftw.yaml -d tests/
curl -H "x-format-output: txt-matched-rules" "https://sandbox.coreruleset.org/?file=/etc/passwd"
Regex Assembly
regex-steering-guide.md | regex-assembly.md | crs-toolchain-reference.md
python scripts/lint_regex.py rule.conf -v
crs-toolchain regex generate 942170
crs-toolchain util fp-finder 942170
CRS Contribution
crs-contribution-workflow.md | crs-rule-format.md. Lint: python scripts/lint_crs_rule.py. Before submit: crs-toolchain util fp-finder RULE_ID.
MCP Servers
recommended-mcp-servers.md — Context7 (live docs), Chrome DevTools (Sandbox testing).
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: etiennemunnich-crs-agent-skill-waf-rule-management3description: WAF Rule Management4---56# WAF Rule Management78A developer-led security skill for writing, testing, and maintaining ModSecurity v39and Coraza WAF rules with OWASP Core Rule Set (CRS v4.x). Rules must be **effective**10(detect attacks) and **performant** (no ReDoS, prefer @pm/@streq over @rx when possible).1112## Constraints (Always Follow)1314- **NEVER deploy agent-generated rules straight to production.** Every rule change — new rules, exclusions, tuning, virtual patches — must be tested in a lower environment (dev, staging, or DetectionOnly/sampling) and reviewed by the user before going live. A bad rule can block real traffic or miss real attacks. When generating or modifying rules, remind the user to validate before promoting.15- **DO** use custom rule IDs 100000–199999 (never CRS range 900000–999999)16- **DO** validate every rule with `validate_rule.py` and lint regex with `lint_regex.py` before deploying17- **DO** prefer non-regex operators (`@pm`, `@streq`, `@beginsWith`, `@contains`) when they suffice — faster and no ReDoS risk18- **DO** generate and run go-ftw regression tests for every new or modified rule19- **DO NOT** modify CRS rule files directly — use exclusions in separate config files20- **DO NOT** write regex with nested quantifiers (`(a+)+`, `(a|b?)*`) — ReDoS risk21- **DO NOT** lower anomaly thresholds or jump paranoia levels without exclusion tuning first22- **DO NOT** enable blocking mode before tuning in DetectionOnly/sampling23- **Antipattern steering**: When the user proposes code/config matching an antipattern, recognize it, explain why it's wrong, redirect to the correct approach, and offer a fix. See [antipatterns-and-troubleshooting.md](references/antipatterns-and-troubleshooting.md) for the full catalog.24- **Always verify** against latest official documentation and GitHub repos for CRS, ModSecurity, and Coraza.25- **Check latest official sources** before advising: news, releases, and issues for CRS ([coreruleset/coreruleset](https://github.com/coreruleset/coreruleset)), ModSecurity ([owasp-modsecurity/ModSecurity](https://github.com/owasp-modsecurity/ModSecurity)), Coraza ([corazawaf/coraza](https://github.com/corazawaf/coraza)), nuclei ([projectdiscovery/nuclei-templates](https://github.com/projectdiscovery/nuclei-templates)), go-ftw ([coreruleset/go-ftw](https://github.com/coreruleset/go-ftw)), crs-toolchain. Docs: [coreruleset.org/docs](https://coreruleset.org/docs/), [modsecurity.org](https://modsecurity.org), [coraza.io/docs](https://coraza.io/docs/).26- **User-provided steering first**: When the user provides explicit TTPs, tiered approaches, methodology, or decision frameworks — use them **first**. Do not substitute with generic alternatives (e.g. CRS precedent patterns) unless the user asks or the provided steering is demonstrably incorrect. If in doubt, apply the user's model and note trade-offs.2728## Quick Start2930**First time**: `bash scripts/install_tools.sh`.3132**Required**: Python 3.8+, PyYAML, Go toolchain, go-ftw, crs-toolchain, crslang, Docker or Finch.33**Optional fallback**: modsec-rules-check (legacy parser; crslang is primary).34**Optional**: cdncheck (ingress discovery).3536> **Container runtime**: `finch` is preferred; `docker` works identically. All `finch compose` / `finch logs` commands are interchangeable with `docker compose` / `docker logs`. Scripts auto-detect the available runtime.3738### SecRule One-Liner3940```41SecRule VARIABLE "@OPERATOR pattern" "id:N,phase:N,ACTION,status:NNN,log,msg:'...',tag:'...',severity:'...'"42```4344Phases: 1=Request Headers, 2=Request Body, 3=Response Headers, 4=Response Body, 5=Logging.45Custom rule IDs: **100000–199999** (avoids CRS conflicts).4647### Essential Commands4849```bash50python scripts/validate_rule.py rule.conf # Validate syntax (crslang first, then legacy)51python scripts/lint_regex.py rule.conf -v # ReDoS/performance lint52python scripts/lint_crs_rule.py rule.conf # CRS convention lint53python scripts/analyze_log.py audit.log --summary # Log analysis54python scripts/analyze_log.py audit.log --explain # Why rules triggered55python scripts/openapi_to_rules.py spec.yaml -o r.conf # OpenAPI → rules56python scripts/validate_exclusion.py --input exclusion.conf --output text # Exclusion safety checks57python scripts/detect_app_profile.py audit.log --output text # App profile hints58go-ftw run --cloud --config assets/docker/.ftw.yaml -d tests/ # Regression tests59bash scripts/new_incident.sh INC-001 "brief title" # Create incident workspace60bash scripts/assemble_rules.sh rules/ # Assemble rule set from directory61bash scripts/engine_integration_compare.sh # Cross-engine ModSec vs Coraza comparison6263# Optional ingress discovery (CDN/cloud/WAF front door)64go install github.com/projectdiscovery/cdncheck/cmd/cdncheck@latest65cdncheck -i app.example.com -jsonl6667# Test environment — choose your engine:68docker compose -f assets/docker/docker-compose.yaml up -d # ModSecurity69docker compose -f assets/docker/docker-compose.coraza.yaml up -d # Coraza7071curl -H "x-format-output: txt-matched-rules" \72 "https://sandbox.coreruleset.org/?file=/etc/passwd" # Sandbox check73```7475---7677## Determine Your Task → Load Reference7879**Load exactly one primary reference** for the task. Add adjacent refs only for edge cases. Full index below.8081| User intent | Load reference |82|-------------|----------------|83| False positive / exclusion | [false-positives-and-tuning.md](references/false-positives-and-tuning.md) + [antipatterns-and-troubleshooting.md](references/antipatterns-and-troubleshooting.md) — includes Post-Upgrade / Regex-Change FP section |84| CRS v3→v4 exception / exclusion migration | [crs-v3-v4-exception-migration.md](references/crs-v3-v4-exception-migration.md) — `ctl:ruleEngine=Off`, plugins, `ver:`, ID checks, REQUEST-900 vs RESPONSE-999 (after [upgrade-and-testing.md](references/upgrade-and-testing.md) for rollout) |85| Attack not blocked / evasion | [antipatterns-and-troubleshooting.md](references/antipatterns-and-troubleshooting.md) §5 (Rule not matching) |86| New rule / custom detection | [variables-and-collections.md](references/variables-and-collections.md) → [actions-reference.md](references/actions-reference.md) → [crs-rule-format.md](references/crs-rule-format.md) + [regex-steering-guide.md](references/regex-steering-guide.md) (effective + performant) |87| Rule validation / Seclang syntax | [crslang-reference.md](references/crslang-reference.md) — crslang is primary; validate_rule.py uses it first |88| OpenAPI → WAF allowlist | [openapi-to-waf.md](references/openapi-to-waf.md) |89| Log analysis / triage | [log-analysis-steering.md](references/log-analysis-steering.md) |90| Anomaly scoring / threshold tuning | [anomaly-scoring.md](references/anomaly-scoring.md) — includes M2M/API scoring models |91| Sampling / DetectionOnly rollout | [sampling-mode.md](references/sampling-mode.md) |92| Regression testing | [go-ftw-reference.md](references/go-ftw-reference.md) |93| ModSecurity + CRS test env | [modsec-crs-testing-reference.md](references/modsec-crs-testing-reference.md) |94| Coraza + CRS / cross-engine | [coraza-testing-reference.md](references/coraza-testing-reference.md) |95| Incident / zero-day triage | [first-responder-risk-runbook.md](references/first-responder-risk-runbook.md) |96| CRS groups, phases, tuning | [crs-tune-rule-steering.md](references/crs-tune-rule-steering.md) |97| CRS contribution / PR | [crs-contribution-workflow.md](references/crs-contribution-workflow.md) |98| Deployment / rollout | [best-practices-modsec-coraza-crs.md](references/best-practices-modsec-coraza-crs.md) |99| Regex / ReDoS / crs-toolchain | [regex-steering-guide.md](references/regex-steering-guide.md) |100| v2→v3 migration | [modsecurity-migration-checklist.md](references/modsecurity-migration-checklist.md) |101| OODA loop / workflow methodology | [ooda-loop-guide.md](references/ooda-loop-guide.md) |102| Developer security lifecycle / CI | [developer-security-workflow.md](references/developer-security-workflow.md) |103104---105106## LRM Default Workflow (Concise)107108For most false-positive and triage tasks, steer with this minimal sequence:1091101. **Observe**: `analyze_log.py --summary --top-rules 20`1112. **Explain**: `analyze_log.py --explain-rule <ID> --detail`1123. **Profile check**: `detect_app_profile.py` (and app package/plugin match)1134. **Tune narrow**: `generate_exclusion.py` (URI + param scoped)1145. **Validate + test**: `validate_exclusion.py` + go-ftw regression115116Use broader discovery tools (`httpx`, `cdncheck`, `nuclei`, `vulnx`) only when the core 5-step flow lacks enough evidence.117118### FP handling steering119120When the user reports a false positive or asks how to handle FPs:1211221. **Capture context first** — Paranoia level, CRS version, engine, app/platform, triggering payload, rule ID + matched variable. Ask if missing.1232. **Post-upgrade FP?** — If user says "after upgrading to vX.Y.Z, rule N fires": follow [false-positives-and-tuning.md](references/false-positives-and-tuning.md) Post-Upgrade / Regex-Change FP section — trace to recent PR, extract Matched Data from logs, check variable-target (headers vs ARGS).1243. **Investigate** — `analyze_log.py --explain-rule <ID> --detail`; search [CRS issues](https://github.com/coreruleset/coreruleset/issues) for the rule ID; run `detect_app_profile.py` for app package match.1254. **Classify** — Use [false-positives-and-tuning.md](references/false-positives-and-tuning.md) FP category routing (natural language, GraphQL, SQL keyword in text, etc.) to choose approach.1265. **Apply narrowest exclusion** — Prefer `ctl:ruleRemoveTargetById` (URI + param scoped) over whole-rule removal. For dynamic variable keys, target exclusion may not work — use URI-scoped `ctl:ruleRemoveById`. Check engine source/docs for exclusion syntax limits.1276. **Validate + regression** — `validate_exclusion.py`; go-ftw with FP test (pass) and attack test (block).128129**Process is paramount**: reproduce, investigate engine behavior, then apply fix. Do not hardcode issue-specific examples — keep steering generic.130131### Evasion / false negative steering132133When the user reports "attack not blocked" or "rule not working":1341351. **Phase** — ARGS/body need phase 2. **Variable** — Is target populated? **Transform** — Encoding bypass? Add t:urlDecodeUni.1362. **Search CRS issues** for evasion/bypass reports on the rule ID.1373. **Content-type** — Test across form, JSON, multipart; content-type bypass is common.1384. If reporting upstream → [CRS false-negative template](https://github.com/coreruleset/coreruleset/issues/new?template=02_false-negative.md).139140Full checklist: [antipatterns-and-troubleshooting.md](references/antipatterns-and-troubleshooting.md) §5 (Rule not matching).141142### Context7143144- **Context7**: Use Context7 (or documentation-lookup skill) **early** when the skill references it — for CVE lookup, CRS rule format, ModSecurity/Coraza docs, go-ftw. Do not wait for the user to ask.145146---147148## DAST/Discovery Tool Preference Order149150Use these tools directly (not wrappers) based on the gap you need to fill:151152| Priority | Tool | Use First When | Why |153|----------|------|----------------|-----|154| 1 | `httpx` | You need live target normalization + HTTP probing | Fast host/URL probing, tech detect, response metadata, CDN hints |155| 2 | `cdncheck` | You need ingress visibility (CDN/cloud/WAF masking) | Confirms front-door providers that may hide origin fingerprints |156| 3 | `nuclei` | You need active DAST checks for known classes/CVEs | High-performance scanner across HTTP/DNS/network/cloud |157| 4 | `nuclei-templates` | You need broad, current detection coverage | Community-curated template corpus used by `nuclei` |158| 5 | `cvemap` (`vulnx`) | You need vuln intelligence prioritization | Search/filter CVEs, KEV/PoC/template context for risk triage |159| 6 | `nvd-cve` MCP server | You need CVE fact lookup inside agent chat | Quick CVE detail/search in MCP-native workflow |160161Practical steering sequence:1621. `httpx` enumerate reachable surfaces and technology clues.1632. `cdncheck` confirm ingress layers and adjust confidence for origin fingerprinting.1643. `nuclei` with curated template scope (start focused, then widen).1654. `cvemap` (`vulnx`) prioritize findings by severity, KEV, exploitability.1665. `nvd-cve` MCP for rapid CVE detail lookup during triage writeups.167168Reference installs:169- `go install github.com/projectdiscovery/httpx/cmd/httpx@latest`170- `go install github.com/projectdiscovery/cdncheck/cmd/cdncheck@latest`171- `go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest`172- `go install github.com/projectdiscovery/cvemap/cmd/vulnx@latest`173- `nuclei -ut` (update templates)174175---176177## Reference Index (Load on Demand)178179| File | Load When |180|------|-----------|181| [antipatterns-and-troubleshooting.md](references/antipatterns-and-troubleshooting.md) | Broken config, bad exclusion, rule not working, CRS reporting |182| [false-positives-and-tuning.md](references/false-positives-and-tuning.md) | FP handling, exclusion decision tree, safe patterns |183| [crs-tune-rule-steering.md](references/crs-tune-rule-steering.md) | CRS groups, phases, request/response, version-aware tuning |184| [anomaly-scoring.md](references/anomaly-scoring.md) | Anomaly threshold tuning, M2M/API scoring models, inbound/outbound |185| [sampling-mode.md](references/sampling-mode.md) | DetectionOnly / sampling rollout strategy |186| [log-analysis-steering.md](references/log-analysis-steering.md) | Audit/error log analysis, top talkers |187| [go-ftw-reference.md](references/go-ftw-reference.md) | Regression tests, test format, cloud mode |188| [modsec-crs-testing-reference.md](references/modsec-crs-testing-reference.md) | ModSecurity + CRS local test env |189| [coraza-testing-reference.md](references/coraza-testing-reference.md) | Coraza / cross-engine testing |190| [crs-application-profiles.md](references/crs-application-profiles.md) | WordPress, Drupal, APIs — app-specific exclusions |191| [crs-rule-format.md](references/crs-rule-format.md) | CRS-style rule writing, metadata |192| [crslang-reference.md](references/crslang-reference.md) | Rule validation (primary), Seclang↔CRSLang conversion |193| [actions-reference.md](references/actions-reference.md) | Rule actions (deny, chain, setvar, ctl) |194| [variables-and-collections.md](references/variables-and-collections.md) | ARGS, headers, TX, etc. |195| [operators-and-transforms.md](references/operators-and-transforms.md) | @rx, @pm, transforms |196| [regex-steering-guide.md](references/regex-steering-guide.md) | Effective + performant rules, ReDoS, operator choice, transforms |197| [openapi-to-waf.md](references/openapi-to-waf.md) | OpenAPI → positive-security rules |198| [first-responder-risk-runbook.md](references/first-responder-risk-runbook.md) | Incident triage, virtual patches |199| [ooda-loop-guide.md](references/ooda-loop-guide.md) | OODA loop methodology mapped to WAF workflows |200| [developer-security-workflow.md](references/developer-security-workflow.md) | Branch-per-change strategy, developer-friendly CI lifecycle |201| [crs-contribution-workflow.md](references/crs-contribution-workflow.md) | CRS PR, go-ftw, nuclei |202| [best-practices-modsec-coraza-crs.md](references/best-practices-modsec-coraza-crs.md) | Deployment, rollout |203| [modsec-directives.md](references/modsec-directives.md) | Engine directives |204| [paranoia-levels.md](references/paranoia-levels.md) | PL rollout |205| [crs-sandbox-reference.md](references/crs-sandbox-reference.md) | Sandbox API, reproducible curl |206| [crs-toolchain-reference.md](references/crs-toolchain-reference.md) | crs-toolchain CLI |207| [regex-assembly.md](references/regex-assembly.md) | .ra files |208| [baseline-testing-tools.md](references/baseline-testing-tools.md) | go-test-waf, nuclei |209| [upgrade-and-testing.md](references/upgrade-and-testing.md) | CRS upgrade |210| [crs-v3-v4-exception-migration.md](references/crs-v3-v4-exception-migration.md) | v3→v4 exclusion files, ctl changes, plugin registry |211| [modsecurity-migration-checklist.md](references/modsecurity-migration-checklist.md) | v2→v3 migration |212| [ja4-ja3-cdn-lb-steering.md](references/ja4-ja3-cdn-lb-steering.md) | TLS fingerprints, CDN |213| [recommended-mcp-servers.md](references/recommended-mcp-servers.md) | Context7, Chrome DevTools MCP |214215**Rule**: Load one primary ref. Add adjacent only for edge cases.216217---218219## Writing New Rules220221**Effective + performant**: Use `@pm`/`@streq`/`@beginsWith` when regex not needed; avoid nested quantifiers; run `lint_regex.py`. See [regex-steering-guide.md](references/regex-steering-guide.md).222223Variables → [variables-and-collections.md](references/variables-and-collections.md) | Operators → [operators-and-transforms.md](references/operators-and-transforms.md) | Actions → [actions-reference.md](references/actions-reference.md) | Format → [crs-rule-format.md](references/crs-rule-format.md)224225```bash226python scripts/validate_rule.py rule.conf && python scripts/lint_regex.py rule.conf -v227python scripts/generate_ftw_test.py rule.conf -o tests/228go-ftw run --cloud --config assets/docker/.ftw.yaml -d tests/229```230231---232233## OpenAPI to WAF Rules234235Allowlist rules from OpenAPI → validate before CRS. See [openapi-to-waf.md](references/openapi-to-waf.md).236237```bash238python scripts/openapi_to_rules.py openapi.yaml -o before-crs-rules.conf239python scripts/validate_rule.py before-crs-rules.conf240```241242---243244## Tuning and False Positives245246See [false-positives-and-tuning.md](references/false-positives-and-tuning.md) and [antipatterns-and-troubleshooting.md](references/antipatterns-and-troubleshooting.md). Exclusion placement: runtime (`ctl:*`) BEFORE CRS include; configure-time (`SecRuleRemove*`) AFTER.247248```bash249python scripts/analyze_log.py audit.log --explain-rule 942100 --detail250python scripts/generate_exclusion.py --rule-id 942100 --uri /api/search --param ARGS:q251python scripts/validate_exclusion.py --input exclusion.conf252go-ftw run --cloud --config assets/docker/.ftw.yaml -d tests/253```254255---256257## Analyzing WAF Logs258259See [log-analysis-steering.md](references/log-analysis-steering.md).260261```bash262python scripts/analyze_log.py audit.log --summary --top-rules 20263python scripts/analyze_log.py audit.log --explain-rule 942100 --detail264python scripts/detect_app_profile.py audit.log --output text265```266267---268269## Testing Rules270271Quick check → [crs-sandbox-reference.md](references/crs-sandbox-reference.md) | Local regression → [go-ftw-reference.md](references/go-ftw-reference.md) | ModSec env → [modsec-crs-testing-reference.md](references/modsec-crs-testing-reference.md) | Coraza → [coraza-testing-reference.md](references/coraza-testing-reference.md)272273```bash274docker compose -f assets/docker/docker-compose.yaml up -d # or docker-compose.coraza.yaml275go-ftw run --cloud --config assets/docker/.ftw.yaml -d tests/276curl -H "x-format-output: txt-matched-rules" "https://sandbox.coreruleset.org/?file=/etc/passwd"277```278279---280281## Regex Assembly282283[regex-steering-guide.md](references/regex-steering-guide.md) | [regex-assembly.md](references/regex-assembly.md) | [crs-toolchain-reference.md](references/crs-toolchain-reference.md)284285```bash286python scripts/lint_regex.py rule.conf -v287crs-toolchain regex generate 942170288crs-toolchain util fp-finder 942170289```290291---292293## CRS Contribution294295[crs-contribution-workflow.md](references/crs-contribution-workflow.md) | [crs-rule-format.md](references/crs-rule-format.md). Lint: `python scripts/lint_crs_rule.py`. Before submit: `crs-toolchain util fp-finder RULE_ID`.296297---298299## MCP Servers300301[recommended-mcp-servers.md](references/recommended-mcp-servers.md) — Context7 (live docs), Chrome DevTools (Sandbox testing).302303---304> Converted and distributed by [TomeVault](https://tomevault.io/claim/etiennemunnich) — claim your Tome and manage your conversions.305<!-- tomevault:4.0:skill_md:2026-04-13 -->