-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
The reference manual states:
This directive will overwrite the action list of the specified rule with the actions provided in the second parameter. … Only the actions that can appear only once are overwritten. The actions that are allowed to appear multiple times in a list, will be appended to the end of the list.
I read this, and I (and ChatGPT 5.2 Codex) both concluded that it means it works like this:
- Load current list.
- Actions that can appear once are removed from the actions list. (Conversely actions that are allowed to appear multiple times are kept)
- From the new list: actions that can only appear a single time are prepended to the result list of the previous step.
- From the new list, actions that can appear multiple times are appended to the result list of the previous step (to ensure that ordering of kept actions from the original list is kept logical)
- This is the new actions list for the rule.
Then I see people talk about lines like this:
SecRule ARGS attack "id:1,phase:2,deny,status:403,msg:'test'"
SecRuleUpdateActionById 1 "msg:'extra_test'"
Assuming msg can occur multiple times, according to the documentation, this should result in the final rule:
SecRule ARGS attack "id:1,phase:2,msg:'test',"msg:'extra_test'"
Yet it seems that that is not what people expect to happen.
Am I mad? Am I ChatGPT? Is the documentation contradictory?
I can't really understand how that would work, given that it clearly states (emphasis mine):
This directive will overwrite the action list of the specified rule…
Clearly the entire action list is overwritten, not updated, not modified, the wording is specific, and a priori I have to assume the documentation is correct until proven different, or there'd be no point to any of this. Therefore, there should be no way that any of the original single-occurrence actions are kept.
The documentation example seems to confirm this logic:
SecRule ARGS attack "phase:2,id:12345,t:lowercase,log,pass,msg:'Message text'"
SecRuleUpdateActionById 12345 "t:none,t:compressWhitespace,deny,status:403,msg:'New message text'"
The effective resulting rule in the previous example will be as follows:
SecRule ARGS attack "phase:2,id:12345,t:lowercase,t:none,t:compressWhitespace,deny,status:403,msg:'New Message text'"
Here it seems that log,pass are both dropped.
There's an old StackOverflow post without a good answer, where the poster draws the same conclusion as me and ChatGPT based on the documentation. However there's an ancient blog post which asserts the complete opposite (though it may be about a different version).
The old list is inherited and overwritten by any new parameters you specify, so you don't need to re-type the whole thing.
Which is strange. Is it inherited or overwritten? It doesn't seem like both can be true. Current documentation states that the old list is overwritten.
Maybe the documentation could be updated to clarify this?
Use Case
In my particular use case we've spun up owasp/modsecurity-crs:nginx-alpine in K8s and we've got it in DetectionOnly mode. We're aggregating the logs and classifying the positives logged. Once we've concluded that a certain rule is always a true positive in our application, we'll switch that rule on to block further attacks. We've chosen this approach since accidentally blocking legitimate requests might cause severe service disruption.
I'm trying to figure out whether I can use e.g. SecRuleUpdateActionById 920350 "ctl:ruleEngine=On", or whether I need to look up the actions configuration for rule 920350 and reproduce it in its entirety, minus the actions that can be added multiple times. The latter would be impractical, but no matter how I try to interpret it, I have to conclude that the former is impossible according to the documentation.
Update
I must be severely misunderstanding something, because adding a configuration line like SecRuleUpdateActionById 920350 "ctl:ruleEngine=On" either before or after the CRS does not change the behaviour at all. It still behaves exactly as the original rule definition. No action is performed.