]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Fix] maps: anchor glob map patterns to match the whole subject
authorVsevolod Stakhov <vsevolod@rspamd.com>
Wed, 8 Jul 2026 08:52:53 +0000 (09:52 +0100)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Wed, 8 Jul 2026 08:53:34 +0000 (09:53 +0100)
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

src/libserver/maps/map_helpers.c
test/functional/cases/001_merged/102_multimap.robot
test/functional/configs/maps/glob.list [new file with mode: 0644]
test/functional/configs/merged-override.conf

index f7b4cfbfcccc42762d0790ff0b8e39f9137d3054..e0112feb9096a52d7f8bf1073dc745824b4d7fc1 100644 (file)
@@ -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 {
index b41face39136abbbd1961e3c1d6487720aa74c99..1db7f684940b2c5e1323f4f1e554f269a027cdc7 100644 (file)
@@ -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 (file)
index 0000000..f836810
--- /dev/null
@@ -0,0 +1,2 @@
+t.co
+*.bit.ly
index d8323c9886b948f75576357e9063251ba28797f9..3d4a6770771779b2f5a04ce9bb73081bf6a019fb 100644 (file)
@@ -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";