Security audit 2026-10-17, finding S4 (low), stage 4. The sidecar ran
rspamd 3.11.1 (December 2024) with default capabilities; upstream is 4.2.2
(2026-10-10), and the line between fixed a heap overflow in
util.lower_utf8, a use-after-free on reload and parser crashes - rspamd
reads every byte a stranger sends to port 25.
A read-only reading of rspamd 3.11.1 and 4.2.2 and of rspamd-docker
v3.11.1+3 and v4.2.2+0, side by side (sources in dev/upstream), found every
function SelfPost relies on unchanged: milter_headers (skip_wanted, the
custom routine, remove 0, create_specific_keyed, get_queue_id from {i}),
the X-Spamd-Result text, multimap (from/smtp, ip, the reject pre-result,
file-map rereading), the image's uid 11333 and CMD. It also found that the
image binds the normal worker (which takes client-named file and shm
inputs) and the controller (default password "q1") on every address,
reachable from any container on the compose network - so:
- image rspamd/rspamd:4.2.2-0 (the one build of 4.2.2; the others float);
- cap_drop: [ALL], no-new-privileges (rspamd starts unprivileged, ports
above 1024, nothing setuid);
- RSPAMD_LOCAL_ADDR=localhost keeps every worker on loopback, and a new
antispam/rspamd/worker-proxy.inc puts the proxy alone on *:11332. rspamd
expands its template syntax in comments too - the first version of that
comment quoted it and the config failed to load; it quotes none now.
Checked in a throwaway container on the test server with the three files
and the fragment's options (dev/server/rspamd-try.sh): proxy on any
address, 11333/11334 on loopback; from a private address a sender's own
verdict headers removed and rspamd's added; X-SelfPost-Filter equal to
openssl's HMAC-SHA256 of the queue id; a denied address refused with the
deny list's message; healthy. The e2e has no rspamd; the live sidecar is
checked at the rollout. Citations re-pointed to 4.2.2.
Docs: guide § Inbound relay (the third file; copy antispam/ again);
CHANGELOG; plan.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
19 lines
1.1 KiB
C++
19 lines
1.1 KiB
C++
# Mounted into the sidecar as /etc/rspamd/local.d/worker-proxy.inc.
|
|
#
|
|
# The milter - the proxy worker - is the one listener SelfPost needs on the
|
|
# compose network. The fragment sets RSPAMD_LOCAL_ADDR=localhost, which keeps
|
|
# every worker on the container's loopback: the normal worker (11333), whose
|
|
# scan accepts a client-named file or shared-memory input, and the controller
|
|
# (11334), whose default password is the well-known "q1" (rspamd 4.2.2,
|
|
# conf/rspamd.conf: each worker's bind_socket is the env variable LOCAL_ADDR,
|
|
# localhost by default, and its port; conf/worker-controller.inc: password =
|
|
# "q1"; the rspamd-docker v4.2.2+0 Dockerfile sets RSPAMD_LOCAL_ADDR=* for all
|
|
# three). This line puts the proxy alone back on every address: a local.d
|
|
# scalar at priority 1 replaces the default one (contrib/libucl/ucl_parser.c,
|
|
# UCL_DUPLICATE_MERGE). The proxy still reaches the normal worker on
|
|
# localhost, as before (security audit 2026-10-17, S4).
|
|
#
|
|
# rspamd expands its template syntax in these files, comments included:
|
|
# quote none of it here.
|
|
bind_socket = "*:11332";
|