Description
I'm trying to use SecAuditEngine + SecAuditLog to emit one log event per transaction (which includes contextual TCP/HTTP information as well as all triggered WAF rules in the messages array). My goal is for each transaction I just get one "WAF log" + one "Envoy access log". This is the SecLang I need:
- SecDefaultAction "phase:1,nolog,auditlog,pass"
- SecDefaultAction "phase:2,nolog,auditlog,pass"
- SecDefaultAction "phase:3,nolog,auditlog,pass"
- SecDefaultAction "phase:4,nolog,auditlog,pass"
- SecDefaultAction "phase:5,nolog,auditlog,pass"
The problem is that Include @crs-setup.conf already sets below:
|
SecDefaultAction "phase:1,log,auditlog,pass" |
|
SecDefaultAction "phase:2,log,auditlog,pass" |
If I try to override this in my own directives, it fails with:
[2026-05-07 09:25:24.791][1][warning][dynamic_modules] [source/extensions/dynamic_modules/abi_impl.cc:57] Failed to load configuration: failed to create WAF from directives: invalid WAF config from string: failed to parse string: failed to compile the directive "secrule": SecDefaultAction already defined for this phase: phase:1,nolog,auditlog,pass
[2026-05-07 09:25:24.791][1][warning][config] [source/extensions/config_subscription/grpc/delta_subscription_state.cc:282] delta config for type.googleapis.com/envoy.config.listener.v3.Listener rejected: Error adding/updating listener(s) gateway/envoy-gateway-proxy/https-local: Failed to create filter config: Failed to initialize dynamic module
[2026-05-07 09:25:24.791][1][warning][config] [source/extensions/config_subscription/grpc/grpc_subscription_impl.cc:138] gRPC config for type.googleapis.com/envoy.config.listener.v3.Listener rejected: Error adding/updating listener(s) gateway/envoy-gateway-proxy/https-local: Failed to create filter config: Failed to initialize dynamic module
So the only option I've found is to not use Include @crs-setup.conf at all, and instead replicate the same directives myself. This is okay-ish since there's not much in there, but not ideal because risks CRS versioning mismatches + risks missing out on any potential additions/changes that maintainers make to crs-setup.conf going forward.
- SecDefaultAction "phase:1,nolog,auditlog,pass"
- SecDefaultAction "phase:2,nolog,auditlog,pass"
- SecDefaultAction "phase:3,nolog,auditlog,pass"
- SecDefaultAction "phase:4,nolog,auditlog,pass"
- SecDefaultAction "phase:5,nolog,auditlog,pass"
- SecAction "id:900120,phase:1,pass,t:none,nolog,tag:'OWASP_CRS',ver:'OWASP_CRS/4.25.0',setvar:tx.early_blocking=1"
- SecAction "id:900990,phase:1,pass,t:none,nolog,tag:'OWASP_CRS',ver:'OWASP_CRS/4.25.0',setvar:tx.crs_setup_version=4250"
Can we somehow expose configuration options for logging? For example in EEP in EG:
dynamicModule:
- name: composer
filterName: coraza-waf
config:
mode: REQUEST_ONLY
telemetry:
auditLog: true
ruleLog: false
directives: ...
Or can we split up crs-setup.conf into two maintained files crs-setup.conf + default-actions.conf?
Full reproduction
Configuration
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
name: envoy-gateway-proxy
namespace: {{ .Release.Namespace }}
spec:
provider:
type: Kubernetes
kubernetes:
envoyDeployment:
container:
env:
- name: GODEBUG
value: "cgocheck=0"
volumeMounts:
- name: dynamic-modules
mountPath: /etc/envoy/dynamic-modules
readOnly: true
pod:
volumes:
- name: dynamic-modules
image:
reference: ghcr.io/tetratelabs/built-on-envoy/composer:0.6.0-dev
pullPolicy: IfNotPresent
dynamicModules:
- name: composer
source:
type: Local
local:
path: /etc/envoy/dynamic-modules/libcomposer.so
doNotClose: true
loadGlobally: false
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyExtensionPolicy
metadata:
name: envoy-gateway-waf
namespace: {{ .Release.Namespace }}
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: envoy-gateway-proxy
dynamicModule:
- name: composer
filterName: coraza-waf
config:
mode: REQUEST_ONLY
directives:
- Include @coraza.conf
- SecRequestBodyLimitAction ProcessPartial
- SecAuditEngine RelevantOnly
- SecAuditLog /dev/stdout
- SecRuleEngine On
- Include @crs-setup.conf
- Include @owasp_crs/*.conf
I get both audit log + logs from individual rules
{
"level": "error",
"ts": 1778142301.534977,
"caller": "coraza/config.go:87",
"msg": "[client \"00.000.000.00\"] Coraza: Warning. SQL Injection Attack Detected via libinjection [file \"@owasp_crs/REQUEST-942-APPLICATION-ATTACK-SQLI.conf\"] [line \"5922\"] [id \"942100\"] [rev \"\"] [msg \"SQL Injection Attack Detected via libinjection\"] [data \"Matched Data: 1&1 found within ARGS:id: 1 OR 1=1\"] [severity \"critical\"] [ver \"OWASP_CRS/4.25.0\"] [maturity \"0\"] [accuracy \"0\"] [tag \"application-multi\"] [tag \"language-multi\"] [tag \"platform-multi\"] [tag \"attack-sqli\"] [tag \"paranoia-level/1\"] [tag \"OWASP_CRS\"] [tag \"OWASP_CRS/ATTACK-SQLI\"] [tag \"capec/1000/152/248/66\"] [hostname \"127.0.0.1\"] [uri \"https://bogus-lab.mcs-work-lab6849-aks.lab.svc.hmgroup.io/anything?id=1+OR+1%3D1\"] [unique_id \"41cc52e8-f8b7-912b-9444-76f3a6441658\"]",
"severity": "critical",
"stacktrace": "github.com/tetratelabs/built-on-envoy/extensions/composer/waf/coraza.NewWAFFromDirectives.newSlogError.func1\n\t/workspace/waf/coraza/config.go:87\ngithub.com/corazawaf/coraza/v3/internal/corazawaf.(*Transaction).MatchRule\n\t/go/pkg/mod/github.com/corazawaf/coraza/v3@v3.7.0/internal/corazawaf/transaction.go:605\ngithub.com/corazawaf/coraza/v3/internal/corazawaf.(*Rule).doEvaluate\n\t/go/pkg/mod/github.com/corazawaf/coraza/v3@v3.7.0/internal/corazawaf/rule.go:401\ngithub.com/corazawaf/coraza/v3/internal/corazawaf.(*Rule).Evaluate\n\t/go/pkg/mod/github.com/corazawaf/coraza/v3@v3.7.0/internal/corazawaf/rule.go:185\ngithub.com/corazawaf/coraza/v3/internal/corazawaf.(*RuleGroup).Eval\n\t/go/pkg/mod/github.com/corazawaf/coraza/v3@v3.7.0/internal/corazawaf/rulegroup.go:261\ngithub.com/corazawaf/coraza/v3/internal/corazawaf.(*Transaction).ProcessRequestBody\n\t/go/pkg/mod/github.com/corazawaf/coraza/v3@v3.7.0/internal/corazawaf/transaction.go:1087\ngithub.com/tetratelabs/built-on-envoy/extensions/composer/waf.(*wafPlugin).handleRequestBody\n\t/workspace/waf/waf.go:435\ngithub.com/tetratelabs/built-on-envoy/extensions/composer/waf.(*wafPlugin).OnRequestHeaders\n\t/workspace/waf/waf.go:231\ngithub.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go/abi.envoy_dynamic_module_on_http_filter_request_headers\n\t/go/pkg/mod/github.com/envoyproxy/envoy/source/extensions/dynamic_modules@v0.0.0-20260423231439-f1dd21b16c24/sdk/go/abi/internal.go:1603\n_cgoexp_0239f516b2d1_envoy_dynamic_module_on_http_filter_request_headers\n\t/go/pkg/mod/github.com/envoyproxy/envoy/source/extensions/dynamic_modules@v0.0.0-20260423231439-f1dd21b16c24/sdk/go/abi/internal.go:1577\nruntime.cgocallbackg1\n\t/usr/local/go/src/runtime/cgocall.go:466\nruntime.cgocallbackg\n\t/usr/local/go/src/runtime/cgocall.go:362\nruntime.cgocallback\n\t/usr/local/go/src/runtime/asm_amd64.s:1160"
}
{
"level": "info",
"ts": 1778142301.535425,
"caller": "coraza/config.go:93",
"msg": "[client \"00.000.000.00\"] Coraza: Access denied (phase 2). Inbound Anomaly Score Exceeded (Total Score: 5) [file \"@owasp_crs/REQUEST-949-BLOCKING-EVALUATION.conf\"] [line \"7701\"] [id \"949110\"] [rev \"\"] [msg \"Inbound Anomaly Score Exceeded (Total Score: 5)\"] [data \"\"] [severity \"unknown\"] [ver \"OWASP_CRS/4.25.0\"] [maturity \"0\"] [accuracy \"0\"] [tag \"anomaly-evaluation\"] [tag \"OWASP_CRS\"] [hostname \"127.0.0.1\"] [uri \"https://example.com/anything?id=1+OR+1%3D1\"] [unique_id \"41cc52e8-f8b7-912b-9444-76f3a6441658\"]",
"severity": "unknown"
}
{
"transaction": {
"timestamp": "2026/05/07 08:25:01",
"unix_timestamp": 1778142301520084241,
"id": "41cc52e8-f8b7-912b-9444-76f3a6441658",
"client_ip": "00.000.000.00",
"client_port": 18389,
"host_ip": "127.0.0.1",
"host_port": 80,
"server_id": "example.com",
"request": {
"method": "GET",
"protocol": "HTTP/2",
"uri": "https://example.com/anything?id=1+OR+1%3D1",
"http_version": "",
"headers": {
":authority": [
"example.com"
],
":method": [
"GET"
],
":path": [
"/anything?id=1+OR+1%3D1"
],
":scheme": [
"https"
],
"accept": [
"*/*"
],
"host": [
"example.com"
],
"user-agent": [
"curl/8.7.1"
],
"x-envoy-external-address": [
"00.000.000.00"
],
"x-forwarded-for": [
"00.000.000.00"
],
"x-forwarded-proto": [
"https"
],
"x-request-id": [
"41cc52e8-f8b7-912b-9444-76f3a6441658"
]
},
"body": "",
"files": null,
"args": {},
"length": 0
},
"response": {
"protocol": "",
"status": 0,
"headers": {},
"body": ""
},
"producer": {
"connector": "",
"version": "",
"server": "",
"rule_engine": "On",
"stopwatch": "1778142301520084241 15634996; combined=1845216, p1=511911, p2=1276041, p3=0, p4=0, p5=57264",
"rulesets": [
"OWASP_CRS/4.25.0"
]
},
"highest_severity": "",
"is_interrupted": true
},
"messages": [
{
"actionset": "",
"message": "",
"error_message": "[client \"00.000.000.00\"] Coraza: Warning. SQL Injection Attack Detected via libinjection [file \"@owasp_crs/REQUEST-942-APPLICATION-ATTACK-SQLI.conf\"] [line \"5922\"] [id \"942100\"] [rev \"\"] [msg \"SQL Injection Attack Detected via libinjection\"] [data \"Matched Data: 1\u00261 found within ARGS:id: 1 OR 1=1\"] [severity \"critical\"] [ver \"OWASP_CRS/4.25.0\"] [maturity \"0\"] [accuracy \"0\"] [tag \"application-multi\"] [tag \"language-multi\"] [tag \"platform-multi\"] [tag \"attack-sqli\"] [tag \"paranoia-level/1\"] [tag \"OWASP_CRS\"] [tag \"OWASP_CRS/ATTACK-SQLI\"] [tag \"capec/1000/152/248/66\"] [hostname \"127.0.0.1\"] [uri \"https://example.com/anything?id=1+OR+1%3D1\"] [unique_id \"41cc52e8-f8b7-912b-9444-76f3a6441658\"]",
"data": null
},
{
"actionset": "",
"message": "",
"error_message": "[client \"00.000.000.00\"] Coraza: Access denied (phase 2). Inbound Anomaly Score Exceeded (Total Score: 5) [file \"@owasp_crs/REQUEST-949-BLOCKING-EVALUATION.conf\"] [line \"7701\"] [id \"949110\"] [rev \"\"] [msg \"Inbound Anomaly Score Exceeded (Total Score: 5)\"] [data \"\"] [severity \"unknown\"] [ver \"OWASP_CRS/4.25.0\"] [maturity \"0\"] [accuracy \"0\"] [tag \"anomaly-evaluation\"] [tag \"OWASP_CRS\"] [hostname \"127.0.0.1\"] [uri \"https://example.com/anything?id=1+OR+1%3D1\"] [unique_id \"41cc52e8-f8b7-912b-9444-76f3a6441658\"]",
"data": null
}
]
}
Description
I'm trying to use
SecAuditEngine+SecAuditLogto emit one log event per transaction (which includes contextual TCP/HTTP information as well as all triggered WAF rules in themessagesarray). My goal is for each transaction I just get one "WAF log" + one "Envoy access log". This is the SecLang I need:The problem is that
Include @crs-setup.confalready sets below:built-on-envoy/extensions/composer/waf/coraza/directives/@crs-setup.conf
Lines 98 to 99 in 644f8d2
If I try to override this in my own directives, it fails with:
So the only option I've found is to not use
Include @crs-setup.confat all, and instead replicate the same directives myself. This is okay-ish since there's not much in there, but not ideal because risks CRS versioning mismatches + risks missing out on any potential additions/changes that maintainers make tocrs-setup.confgoing forward.Can we somehow expose configuration options for logging? For example in EEP in EG:
Or can we split up
crs-setup.confinto two maintained filescrs-setup.conf+default-actions.conf?Full reproduction
Configuration
I get both audit log + logs from individual rules
{ "level": "error", "ts": 1778142301.534977, "caller": "coraza/config.go:87", "msg": "[client \"00.000.000.00\"] Coraza: Warning. SQL Injection Attack Detected via libinjection [file \"@owasp_crs/REQUEST-942-APPLICATION-ATTACK-SQLI.conf\"] [line \"5922\"] [id \"942100\"] [rev \"\"] [msg \"SQL Injection Attack Detected via libinjection\"] [data \"Matched Data: 1&1 found within ARGS:id: 1 OR 1=1\"] [severity \"critical\"] [ver \"OWASP_CRS/4.25.0\"] [maturity \"0\"] [accuracy \"0\"] [tag \"application-multi\"] [tag \"language-multi\"] [tag \"platform-multi\"] [tag \"attack-sqli\"] [tag \"paranoia-level/1\"] [tag \"OWASP_CRS\"] [tag \"OWASP_CRS/ATTACK-SQLI\"] [tag \"capec/1000/152/248/66\"] [hostname \"127.0.0.1\"] [uri \"https://bogus-lab.mcs-work-lab6849-aks.lab.svc.hmgroup.io/anything?id=1+OR+1%3D1\"] [unique_id \"41cc52e8-f8b7-912b-9444-76f3a6441658\"]", "severity": "critical", "stacktrace": "github.com/tetratelabs/built-on-envoy/extensions/composer/waf/coraza.NewWAFFromDirectives.newSlogError.func1\n\t/workspace/waf/coraza/config.go:87\ngithub.com/corazawaf/coraza/v3/internal/corazawaf.(*Transaction).MatchRule\n\t/go/pkg/mod/github.com/corazawaf/coraza/v3@v3.7.0/internal/corazawaf/transaction.go:605\ngithub.com/corazawaf/coraza/v3/internal/corazawaf.(*Rule).doEvaluate\n\t/go/pkg/mod/github.com/corazawaf/coraza/v3@v3.7.0/internal/corazawaf/rule.go:401\ngithub.com/corazawaf/coraza/v3/internal/corazawaf.(*Rule).Evaluate\n\t/go/pkg/mod/github.com/corazawaf/coraza/v3@v3.7.0/internal/corazawaf/rule.go:185\ngithub.com/corazawaf/coraza/v3/internal/corazawaf.(*RuleGroup).Eval\n\t/go/pkg/mod/github.com/corazawaf/coraza/v3@v3.7.0/internal/corazawaf/rulegroup.go:261\ngithub.com/corazawaf/coraza/v3/internal/corazawaf.(*Transaction).ProcessRequestBody\n\t/go/pkg/mod/github.com/corazawaf/coraza/v3@v3.7.0/internal/corazawaf/transaction.go:1087\ngithub.com/tetratelabs/built-on-envoy/extensions/composer/waf.(*wafPlugin).handleRequestBody\n\t/workspace/waf/waf.go:435\ngithub.com/tetratelabs/built-on-envoy/extensions/composer/waf.(*wafPlugin).OnRequestHeaders\n\t/workspace/waf/waf.go:231\ngithub.com/envoyproxy/envoy/source/extensions/dynamic_modules/sdk/go/abi.envoy_dynamic_module_on_http_filter_request_headers\n\t/go/pkg/mod/github.com/envoyproxy/envoy/source/extensions/dynamic_modules@v0.0.0-20260423231439-f1dd21b16c24/sdk/go/abi/internal.go:1603\n_cgoexp_0239f516b2d1_envoy_dynamic_module_on_http_filter_request_headers\n\t/go/pkg/mod/github.com/envoyproxy/envoy/source/extensions/dynamic_modules@v0.0.0-20260423231439-f1dd21b16c24/sdk/go/abi/internal.go:1577\nruntime.cgocallbackg1\n\t/usr/local/go/src/runtime/cgocall.go:466\nruntime.cgocallbackg\n\t/usr/local/go/src/runtime/cgocall.go:362\nruntime.cgocallback\n\t/usr/local/go/src/runtime/asm_amd64.s:1160" } { "level": "info", "ts": 1778142301.535425, "caller": "coraza/config.go:93", "msg": "[client \"00.000.000.00\"] Coraza: Access denied (phase 2). Inbound Anomaly Score Exceeded (Total Score: 5) [file \"@owasp_crs/REQUEST-949-BLOCKING-EVALUATION.conf\"] [line \"7701\"] [id \"949110\"] [rev \"\"] [msg \"Inbound Anomaly Score Exceeded (Total Score: 5)\"] [data \"\"] [severity \"unknown\"] [ver \"OWASP_CRS/4.25.0\"] [maturity \"0\"] [accuracy \"0\"] [tag \"anomaly-evaluation\"] [tag \"OWASP_CRS\"] [hostname \"127.0.0.1\"] [uri \"https://example.com/anything?id=1+OR+1%3D1\"] [unique_id \"41cc52e8-f8b7-912b-9444-76f3a6441658\"]", "severity": "unknown" } { "transaction": { "timestamp": "2026/05/07 08:25:01", "unix_timestamp": 1778142301520084241, "id": "41cc52e8-f8b7-912b-9444-76f3a6441658", "client_ip": "00.000.000.00", "client_port": 18389, "host_ip": "127.0.0.1", "host_port": 80, "server_id": "example.com", "request": { "method": "GET", "protocol": "HTTP/2", "uri": "https://example.com/anything?id=1+OR+1%3D1", "http_version": "", "headers": { ":authority": [ "example.com" ], ":method": [ "GET" ], ":path": [ "/anything?id=1+OR+1%3D1" ], ":scheme": [ "https" ], "accept": [ "*/*" ], "host": [ "example.com" ], "user-agent": [ "curl/8.7.1" ], "x-envoy-external-address": [ "00.000.000.00" ], "x-forwarded-for": [ "00.000.000.00" ], "x-forwarded-proto": [ "https" ], "x-request-id": [ "41cc52e8-f8b7-912b-9444-76f3a6441658" ] }, "body": "", "files": null, "args": {}, "length": 0 }, "response": { "protocol": "", "status": 0, "headers": {}, "body": "" }, "producer": { "connector": "", "version": "", "server": "", "rule_engine": "On", "stopwatch": "1778142301520084241 15634996; combined=1845216, p1=511911, p2=1276041, p3=0, p4=0, p5=57264", "rulesets": [ "OWASP_CRS/4.25.0" ] }, "highest_severity": "", "is_interrupted": true }, "messages": [ { "actionset": "", "message": "", "error_message": "[client \"00.000.000.00\"] Coraza: Warning. SQL Injection Attack Detected via libinjection [file \"@owasp_crs/REQUEST-942-APPLICATION-ATTACK-SQLI.conf\"] [line \"5922\"] [id \"942100\"] [rev \"\"] [msg \"SQL Injection Attack Detected via libinjection\"] [data \"Matched Data: 1\u00261 found within ARGS:id: 1 OR 1=1\"] [severity \"critical\"] [ver \"OWASP_CRS/4.25.0\"] [maturity \"0\"] [accuracy \"0\"] [tag \"application-multi\"] [tag \"language-multi\"] [tag \"platform-multi\"] [tag \"attack-sqli\"] [tag \"paranoia-level/1\"] [tag \"OWASP_CRS\"] [tag \"OWASP_CRS/ATTACK-SQLI\"] [tag \"capec/1000/152/248/66\"] [hostname \"127.0.0.1\"] [uri \"https://example.com/anything?id=1+OR+1%3D1\"] [unique_id \"41cc52e8-f8b7-912b-9444-76f3a6441658\"]", "data": null }, { "actionset": "", "message": "", "error_message": "[client \"00.000.000.00\"] Coraza: Access denied (phase 2). Inbound Anomaly Score Exceeded (Total Score: 5) [file \"@owasp_crs/REQUEST-949-BLOCKING-EVALUATION.conf\"] [line \"7701\"] [id \"949110\"] [rev \"\"] [msg \"Inbound Anomaly Score Exceeded (Total Score: 5)\"] [data \"\"] [severity \"unknown\"] [ver \"OWASP_CRS/4.25.0\"] [maturity \"0\"] [accuracy \"0\"] [tag \"anomaly-evaluation\"] [tag \"OWASP_CRS\"] [hostname \"127.0.0.1\"] [uri \"https://example.com/anything?id=1+OR+1%3D1\"] [unique_id \"41cc52e8-f8b7-912b-9444-76f3a6441658\"]", "data": null } ] }