-
Notifications
You must be signed in to change notification settings - Fork 575
Description
What happened?
While trying to add the Core Rule Set plugin for Google OAuth, I noticed that the rule below was never fully executed as expected:
SecRule &ARGS_GET:scope "@eq 1" \
"id:9505110,\
phase:2,\
pass,\
t:none,\
nolog,\
ver:'google-oauth2-plugin/1.0.0',\
chain"
SecRule REQUEST_METHOD "@streq GET" \
"chain"
SecRule &ARGS_GET:code "@eq 1" \
"chain"
SecRule ARGS_GET:scope "@rx ^(?:email|profile|openid)(?: email| profile| openid| https://www\.googleapis\.com/auth/(?:userinfo\.email|userinfo\.profile|userinfo\.openid|drive\.metadata\.readonly|drive\.file|drive\.readonly))+$" \
"t:none,t:urlDecodeUni,t:lowercase,\
setvar:'tx.google-oauth2-plugin_callback_detected=1'"
When displaying the debug log, here is the line corresponding to this rule:
time="2026-02-09T14:04:34Z" level=debug msg="Evaluating operator: NO MATCH" arg=2 band=inband chain_rule_ref="_inline_#L169" module=acquisition.appsec operator_data=1 operator_function=@eq rule_id=9505110 rule_ref="_inline_#L708" runner_uuid=65ade97a-c09f-4537-8f0c-1651d056b51a tx_id=9e7a2a1b-2c34-44da-856f-b744cfbec42e type=appsec variable=ARGS_GET
This means that coraza is counting two elements for each URL parameter, while the condition expects only 1. However, I have double-checked and confirmed that my request contains exactly one code argument and one scope argument, no duplicates.
What did you expect to happen?
This rule is known to work; I already use it with ModSecurity. It should work here as well.
How can we reproduce it (as minimally and precisely as possible)?
Set up any rule with a condition like SecRule &ARGS_GET:whatever "@eq 1" and use the URL http://example.com?whatever. The count (arg in the log line) will be 2 instead of 1.
Anything else we need to know?
Yes, I’ve read the code and I think I know where the issue comes from.
In the processRequest() function (in appsec_runner.go), the code calls coraza function AddGetRequestArgument() for each URL parameter, and then the ProcessURI() function is called:
for k, v := range request.Args {
for _, vv := range v {
state.Tx.AddGetRequestArgument(k, vv)
}
}
state.Tx.ProcessURI(request.URI, request.Method, request.Proto)However, in Coraza, ProcessURI() also calls AddGetRequestArgument() for each URL parameter: see here then here.
If you comment out the for loop in processRequest() (the one copied above), the argument count performed by coraza is correct, and the Google OAuth rule works perfectly as expected.
Crowdsec version
Details
$ cscli version
version: v1.7.5-48-g1df2c557-dirty
Codename: alphaga
BuildDate: 2026-02-09_16:47:08
GoVersion: 1.25.7
Platform: docker
libre2: C++
User-Agent: crowdsec/v1.7.5-48-g1df2c557-dirty-docker
Constraint_parser: >= 1.0, <= 3.0
Constraint_scenario: >= 1.0, <= 3.0
Constraint_api: v1
Constraint_acquis: >= 1.0, < 2.0
Built-in optional components: cscli_setup, datasource_appsec, datasource_cloudwatch, datasource_docker, datasource_file, datasource_http, datasource_journalctl, datasource_k8s-audit, datasource_kafka, datasource_kinesis, datasource_loki, datasource_s3, datasource_syslog, datasource_victorialogs, datasource_wineventlog, db_mysql, db_postgres, db_sqliteOS version
Details
KubernetesEnabled collections and parsers
Details
$ cscli hub list -o raw
Loaded: 159 parsers, 11 postoverflows, 773 scenarios, 9 contexts, 5 appsec-configs, 176 appsec-rules, 159 collections
name,status,version,description,type
crowdsecurity/dateparse-enrich,enabled,0.2,,parsers
crowdsecurity/geoip-enrich,enabled,0.5,"Populate event with geoloc info : as, country, coords, source range.",parsers
crowdsecurity/public-dns-allowlist,enabled,0.1,Allow events from public DNS servers,parsers
crowdsecurity/sshd-logs,enabled,3.1,Parse openSSH logs,parsers
crowdsecurity/sshd-success-logs,enabled,0.1,Parse successful ssh logins,parsers
crowdsecurity/syslog-logs,enabled,1.0,,parsers
crowdsecurity/whitelists,enabled,0.3,Whitelist events from private ipv4 addresses,parsers
crowdsecurity/cdn-whitelist,enabled,0.4,Whitelist CDN providers,postoverflows
crowdsecurity/rdns,enabled,0.3,Lookup the DNS associated to the source IP only for overflows,postoverflows
crowdsecurity/seo-bots-whitelist,enabled,0.5,Whitelist good search engine crawlers,postoverflows
crowdsecurity/ssh-bf,enabled,0.3,Detect ssh bruteforce,scenarios
crowdsecurity/ssh-cve-2024-6387,enabled,0.2,Detect exploitation attempt of CVE-2024-6387,scenarios
crowdsecurity/ssh-generic-test,enabled,0.2,Crowdsec Generic Test Scenario: SSH brute force trigger,scenarios
crowdsecurity/ssh-refused-conn,enabled,0.1,Detect sshd refused connections,scenarios
crowdsecurity/ssh-slow-bf,enabled,0.4,Detect slow ssh bruteforce,scenarios
crowdsecurity/ssh-time-based-bf,enabled,0.2,Detect time-based ssh bruteforce attempts that evade rate limiting (with false positive reduction),scenarios
crowdsecurity/bf_base,enabled,0.1,,contexts
crowdsecurity/linux,enabled,0.3,core linux support : syslog+geoip+ssh,collections
crowdsecurity/sshd,enabled,0.8,sshd support : parser and brute-force detection,collections
crowdsecurity/whitelist-good-actors,enabled,0.2,Good actors whitelists,collectionsAcquisition config
Details
# On Linux:
$ cat /etc/crowdsec/acquis.yaml /etc/crowdsec/acquis.d/*
# paste output here
# On Windows:
C:\> Get-Content C:\ProgramData\CrowdSec\config\acquis.yaml
# paste output hereConfig show
Details
$ cscli config show
# paste output herePrometheus metrics
Details
$ cscli metrics
# paste output here