From a62aac2c4567183ed08fc88967426f7136bc27fc Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 9 Oct 2026 19:59:19 +0000 Subject: [PATCH] Restrict the Rspamd controller socket to root and the mail user The controller socket accepts unauthenticated commands and was world-writable (0666), so any local service could retrain the spam filter or change its maps. It is now 0660, group virtualMail: root (the admin rspamc wrapper) and Dovecot's spam/ham learning (mail processes run with gid virtualMail) keep access. Rspamd joins that group only to be allowed to chown the socket; mail homes are 0700 and mail files 0600. Closes #19 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01G22o7QQ17GRtkCqpJNFr9B --- modules/mail.nix | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/modules/mail.nix b/modules/mail.nix index 73cb32c..a87ebde 100644 --- a/modules/mail.nix +++ b/modules/mail.nix @@ -167,6 +167,23 @@ in ); # --- Rspamd ----------------------------------------------------------------- + # The controller socket accepts unauthenticated commands (retrain Bayes, + # change maps). The mail module makes it world-writable (0666); restrict it + # to root (the admin `rspamc` wrapper) and the mail user, whose Dovecot + # processes call rspamc to learn spam/ham when mail is moved to/from Junk. + services.rspamd.workers.controller.bindSockets = lib.mkForce [ + { + socket = "/run/rspamd/worker-controller.sock"; + mode = "0660"; + owner = config.services.rspamd.user; + group = config.mailserver.storage.group; + } + ]; + # Rspamd runs unprivileged and may only hand the socket to a group it is + # in. The group grants nothing else: mail homes are 0700 and mail files are + # written with umask 0077. + systemd.services.rspamd.serviceConfig.SupplementaryGroups = [ config.mailserver.storage.group ]; + services.rspamd.locals = { # Enforce the sender's published DMARC policy instead of only scoring it. # This is what stops spoofed mail claiming to be from paypal.com & co.