SecLang YAML Structure
Structured SecLang representation used by kubeWAF CRDs
This page documents the structured representation used in SecRule.spec.secLangRules[].
Top-Level Rule
- metadata: SecRuleMetadata
conditions: []Condition
actions: SecRuleActions
chainedRule: bool
secMarker: stringMetadata
metadata:
id: 942100
phase: "2"
message: "SQL Injection Attack Detected"
severity: CRITICAL
tags:
- attack-sqli
- OWASP_CRS
- paranoia-level/2Supported severities: EMERGENCY, ALERT, CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG.
Conditions
A condition describes when the rule should trigger.
Variable Form
conditions:
- variables:
- name: REQUEST_URI
- name: ARGS_GET
collection: id # optional member of collection
operator:
name: rx
value: (?:union|select|--)
negate: falseCollection / TX Form (common in CRS)
conditions:
- collections:
- name: TX
arguments:
- DETECTION_PARANOIA_LEVEL
operator:
name: lt
value: "1"Always-Match (initialization rules)
conditions:
- always-match: trueOperators
| Name | Example Value | Notes |
|---|---|---|
rx | (?i)select.*from | Most common |
streq, contains, startswith, endsWith | admin | String ops |
eq, gt, ge, lt, le | 5 | Numeric |
ipMatch | 192.168.0.0/16,10.0.0.0/8 | |
detectSQLi | (no value) | Uses libinjection |
detectXSS | (no value) | |
geoLookup | (no value) | Requires GeoIP data in Wasm image |
Actions
Disruptive Actions
These decide whether the request continues:
disruptive:
disruptiveActionType: deny | block | allow | pass | drop | redirect
status: "403" # for deny/block
redirectUrl: "https://..."Flow Control
flow:
- flowActionType: skip
value: "950000" # skip next N rules
- flowActionType: skipAfter
value: END-REQUEST-920 # skip to markerNon-Disruptive Actions
These modify state or logging without stopping evaluation:
nonDisruptive:
- nonDisruptiveActionType: setvar
value: TX.inbound_anomaly_score_pl1=+5
- nonDisruptiveActionType: msg
value: "Attack detected on %{REQUEST_URI}"
- nonDisruptiveActionType: logdata
value: "%{MATCHED_VAR}"
- nonDisruptiveActionType: ctl
value: ruleRemoveById=942100
- nonDisruptiveActionType: nologChaining
To express "condition A AND condition B":
- metadata: { id: 942100, ... }
conditions: [ condition A ]
actions:
disruptive: { disruptiveActionType: pass }
chainedRule: true
- metadata: { ... same id ... }
conditions: [ condition B ]
actions:
disruptive: { disruptiveActionType: block }The converter automatically emits the chain action on the first part.
SecMarker
A marker rule looks like this:
- secMarker: END-REQUEST-920-PROTOCOL-ENFORCEMENT
metadata:
id: 0
phase: "1"
conditions:
- always-match: true
actions:
nonDisruptive:
- nonDisruptiveActionType: nologLater rules can skipAfter: END-REQUEST-920-PROTOCOL-ENFORCEMENT.
Complete Realistic Example
See the CRS samples in the repository (config/samples/crs/) — they are the best reference for complex real-world rules including heavy use of TX variables, ctl actions, and chaining.
Conversion Guarantees
The controller uses the same crslang library that the CRS converter uses. The generated .status.secRuleString is what the WAF engine compiles (modsecurity-proxy-wasm).
If you ever want to debug "why isn't my rule matching?", copy the secRuleString value and exercise it against a local Envoy + modsecurity-proxy-wasm setup (see that module’s tests).
Full CRD Schema
For every possible field and validation rule, see the generated CRD:
Next: read the Troubleshooting page.