From: Vsevolod Stakhov Date: Wed, 8 Jul 2026 08:52:53 +0000 (+0100) Subject: [Fix] maps: anchor glob map patterns to match the whole subject X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=06cf98f2f5e9ff13141a7ccf6498ac4e4d53cb46;p=thirdparty%2Frspamd.git [Fix] maps: anchor glob map patterns to match the whole subject Glob map entries were compiled into unanchored regexps and matched with substring search semantics, so a `t.co` entry matched `walmart.com` and `*.bit.ly` matched `foo.bit.ly.evil.com`. Wrap the translated pattern into `^(?:...)$` at map load time so glob entries match the subject as a whole: bare names match exactly, wildcards match only what they say. This affects all glob maps: multimap glob/glob_multi, url_redirector redirector_hosts_map, dkim_signing/arc signing_table and key_table, mx_check exclusions and the rbl glob returncodes matcher. Maps that relied on the accidental substring behaviour must now use explicit wildcards. Fixes #6125 --- diff --git a/src/libserver/maps/map_helpers.c b/src/libserver/maps/map_helpers.c index f7b4cfbfcc..e0112feb90 100644 --- a/src/libserver/maps/map_helpers.c +++ b/src/libserver/maps/map_helpers.c @@ -685,9 +685,14 @@ void rspamd_map_helper_insert_re(gpointer st, gconstpointer key, gconstpointer v /* Check regexp stuff */ if (re_map->map_flags & RSPAMD_REGEXP_MAP_FLAG_GLOB) { + char *anchored; + escaped = rspamd_str_regexp_escape(key, strlen(key), &escaped_len, RSPAMD_REGEXP_ESCAPE_GLOB | RSPAMD_REGEXP_ESCAPE_UTF); - re = rspamd_regexp_new(escaped, NULL, &err); + /* Glob semantics: the pattern must match the subject as a whole */ + anchored = g_strdup_printf("^(?:%s)$", escaped); + re = rspamd_regexp_new(anchored, NULL, &err); + g_free(anchored); g_free(escaped); } else { diff --git a/test/functional/cases/001_merged/102_multimap.robot b/test/functional/cases/001_merged/102_multimap.robot index b41face391..1db7f68494 100644 --- a/test/functional/cases/001_merged/102_multimap.robot +++ b/test/functional/cases/001_merged/102_multimap.robot @@ -113,6 +113,26 @@ MAP - FROM REGEXP MISS ... Settings={symbols_enabled = [REGEXP_MAP]} Do Not Expect Symbol REGEXP_MAP +MAP - FROM GLOB EXACT HIT + Scan File ${MESSAGE} From=user@t.co + ... Settings={symbols_enabled = [GLOB_MAP]} + Expect Symbol GLOB_MAP + +MAP - FROM GLOB SUBSTRING MISS + Scan File ${MESSAGE} From=user@walmart.com + ... Settings={symbols_enabled = [GLOB_MAP]} + Do Not Expect Symbol GLOB_MAP + +MAP - FROM GLOB WILDCARD HIT + Scan File ${MESSAGE} From=user@foo.bit.ly + ... Settings={symbols_enabled = [GLOB_MAP]} + Expect Symbol GLOB_MAP + +MAP - FROM GLOB WILDCARD SUPERSTRING MISS + Scan File ${MESSAGE} From=user@foo.bit.ly.evil.com + ... Settings={symbols_enabled = [GLOB_MAP]} + Do Not Expect Symbol GLOB_MAP + MAP - RCPT DOMAIN HIT Scan File ${MESSAGE} Rcpt=user@example.com ... Settings={symbols_enabled = [RCPT_DOMAIN]} diff --git a/test/functional/configs/maps/glob.list b/test/functional/configs/maps/glob.list new file mode 100644 index 0000000000..f836810f17 --- /dev/null +++ b/test/functional/configs/maps/glob.list @@ -0,0 +1,2 @@ +t.co +*.bit.ly diff --git a/test/functional/configs/merged-override.conf b/test/functional/configs/merged-override.conf index d8323c9886..3d4a677077 100644 --- a/test/functional/configs/merged-override.conf +++ b/test/functional/configs/merged-override.conf @@ -77,6 +77,12 @@ multimap { map = "{= env.TESTDIR =}/configs/maps/regexp.list"; require_symbols = "(R_SPF_ALLOW|R_SPF_DNSFAIL) & REGEXP_MAP & !FROM_MAP"; } + GLOB_MAP { + type = "from"; + filter = "email:domain"; + glob = true; + map = "{= env.TESTDIR =}/configs/maps/glob.list"; + } RCPT_DOMAIN { type = "rcpt"; filter = "email:domain";