]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Fix] fuzzy: stop sharing extensions for our own senders
authorVsevolod Stakhov <vsevolod@rspamd.com>
Sun, 9 Aug 2026 13:04:00 +0000 (14:04 +0100)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Sun, 9 Aug 2026 20:58:43 +0000 (21:58 +0100)
fuzzy_cmd_write_extensions() shipped task->from_addr to the storage
whenever the rule did not set no_share. On a deployment that runs fuzzy
checks on outbound or authenticated submission traffic that address is
the operator's own user rather than a third party, so their users' IP
addresses ended up on the public fuzzy servers.

The extensions must describe the sender and only the sender, so omit
them entirely for authenticated tasks and for sources in our own
networks. Nothing of value is lost: such addresses are noise in an IP
reputation model and are exactly the RFC1918 and loopback values that
had to be filtered downstream anyway.

Also honour what the code already claimed and skip the extensions for
rules that talk to the storage in plain text, where they would otherwise
travel in the clear.

src/plugins/fuzzy_check.c

index be154562425d65bdbdb147cd309ab0d1cb5f5962..8edec2ea8052a5280c5e9eec8b7972203619b9be 100644 (file)
@@ -3553,13 +3553,49 @@ fuzzy_rule_check_mimepart(struct rspamd_task *task,
 
 #define MAX_FUZZY_DOMAIN 64
 
+/*
+ * Extensions describe the sender: a third party that has chosen to send mail
+ * into the world. They must never describe the recipient, our own users or our
+ * own policy, hence they are omitted when:
+ *
+ * - the rule opts out of sharing;
+ * - the storage is talked to in plain text, as the extensions would then
+ *   travel in the clear (for sanity + privacy);
+ * - the message has been submitted by an authenticated user or comes from one
+ *   of our own networks. On outbound or submission traffic the source address
+ *   is our own user rather than a third party; such addresses are also noise
+ *   in an IP reputation model, so nothing of value is lost;
+ * - we have no source address at all, which makes the rest of the telemetry
+ *   useless anyway (e.g. a message scanned from a file).
+ */
+static gboolean
+fuzzy_rule_shares_extensions(struct rspamd_task *task,
+                                                        struct fuzzy_rule *rule)
+{
+       if (rule->no_share || !fuzzy_rule_has_encryption(rule)) {
+               return FALSE;
+       }
+
+       if (task->auth_user != NULL) {
+               return FALSE;
+       }
+
+       if (task->from_addr == NULL ||
+               rspamd_inet_address_get_af(task->from_addr) == AF_UNIX ||
+               rspamd_ip_is_local_cfg(task->cfg, task->from_addr)) {
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
 static unsigned int
 fuzzy_cmd_extension_length(struct rspamd_task *task,
                                                   struct fuzzy_rule *rule)
 {
        unsigned int total = 0;
 
-       if (rule->no_share) {
+       if (!fuzzy_rule_shares_extensions(task, rule)) {
                return 0;
        }
 
@@ -3593,7 +3629,7 @@ fuzzy_cmd_write_extensions(struct rspamd_task *task,
 {
        unsigned int written = 0;
 
-       if (rule->no_share) {
+       if (!fuzzy_rule_shares_extensions(task, rule)) {
                return 0;
        }