<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Rspamd Changelog</title>
    <link>https://docs.rspamd.com/changelog</link>
    <description>Release notes and changelog for Rspamd spam filtering system</description>
    <language>en</language>
    <lastBuildDate>Fri, 19 Jun 2026 14:57:34 GMT</lastBuildDate>
    <atom:link href="https://docs.rspamd.com/rss/changelog.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title>Rspamd 4.1.1 - Patch Release with checkv3 Content Negotiation, Neural Extensibility, CSS Hidden-Text Detection, and 4.1.0 Regression Fixes</title>
      <link>https://docs.rspamd.com/changelog/4.1.1</link>
      <guid isPermaLink="false">https://docs.rspamd.com/changelog/4.1.1</guid>
      <pubDate>Fri, 19 Jun 2026 00:00:00 GMT</pubDate>
      <description><![CDATA[<h2>Rspamd 4.1.1 - Patch Release with checkv3 Content Negotiation, Neural Extensibility, CSS Hidden-Text Detection, and 4.1.0 Regression Fixes</h2><h3>Added</h3><ul><li>**/checkv3 content negotiation**: The `/checkv3` reply now honours the client&apos;s `Accept` and `Accept-Encoding` headers at the single `reply_v3` chokepoint shared by the scan worker, `rspamd_proxy`, and the controller. `application/json` / `application/msgpack` yield a plain v2-style single-body reply, `message/rfc822` a `multipart/mixed` envelope, and `multipart/form-data` (also the default for an absent or wildcard `Accept`) a true form-data envelope; an `Accept` listing only unsupported types returns `406 Not Acceptable`. Compression is negotiated separately — `zstd` when offered, identity otherwise — and `Vary: Accept, Accept-Encoding` is always advertised. `rspamc` now requests `multipart/form-data` and accepts any `multipart/` subtype ([#6083](https://github.com/rspamd/rspamd/pull/6083))</li><li>**CSS hidden-text detection**: The invisible-text detector learns several more CSS tricks used to dilute visible spam with hidden ham text — off-screen positioning (`position:absolute|fixed` with a large negative `left`/`top`), image-replacement `text-indent`, `clip` / `clip-path` collapsing the element to zero area (`rect(0,0,0,0)`, `inset(100%)`, `circle(0)`), `visibility:collapse`, and tiny font sizes (≤ 3px). These are now modelled as a hidden display so the effect correctly propagates to descendants, replacing a fragile substring heuristic that only bumped a feature counter and never actually hid the text</li><li>**Zip-bomb extraction limits**: `lua_archive` (`unpack` / `unzip` / `untar`) gains an optional `opts` table that caps extraction while reading, so a tiny hostile archive can no longer expand to gigabytes and OOM the worker: `max_output` (total uncompressed bytes), `max_file_size` (per-member cap, truncated at the cap), `max_files` (member count), and `max_ratio` (per-member uncompressed/compressed ratio). The ratio uses real compressed bytes consumed, checked per chunk above a 64 KiB floor, so a bomb is stopped early even with no size cap set. All limits are opt-in (0/absent = unlimited), preserving the previous behaviour, and a second boolean return flags truncation so a capped extraction is never mistaken for a complete one</li><li>**Byte-distribution statistics for rspamd_text**: New methods on the `rspamd_text` class expose ENT-style byte statistics for content analysis — `entropy()`, `byte_mean()`, `byte_deviation(mean)`, `serial_correlation()`, and `monte_carlo_pi()`. Each takes an optional 1-based `(start, len)` range (consistent with the rest of the slicing API), runs O(n) over a single shared histogram pass, and produces deterministic, bit-reproducible results ([#6106](https://github.com/rspamd/rspamd/pull/6106))</li><li>**zlib/YARA-compatible CRC-32**: Standard CRC-32 (poly `0xEDB88320`) is now available as `rspamd_text:crc32([start[, len]])`, `rspamd_util.crc32(input[, start, len])`, and a streaming `rspamd_cryptobox_hash.create_specific(&quot;crc32&quot;)`, bit-exact with `zlib crc32()` and YARA&apos;s `hash.crc32` (e.g. `&quot;123456789&quot;` → `0xCBF43926`). The text/util forms return a Lua integer over a zero-copy 1-based slice with no buffer copy</li><li>**Explicit multipattern SOM flag**: `RSPAMD_MULTIPATTERN_SOM` (`rspamd_trie.flags.som`) explicitly requests start-of-match offsets, overriding the incompatible single-match flag. The offset convention is now documented — 1-based pattern id, 0-based byte offsets, start inclusive and end exclusive (so `end - start` is the match length) — and the regex fallback used when hyperscan is unavailable now reports the true start/end from the PCRE search instead of a bogus `end - strlen(pattern)` for variable-length matches ([#6105](https://github.com/rspamd/rspamd/pull/6105))</li><li>**Pluggable neural registries**: The neural plugin becomes an extension point so third-party (including closed-source) modules can add feature providers and network topologies without patching the core. `register_architecture(name, builder)` / `get_architecture(name)` join the existing `register_provider`; the built-in `symbol`, `embedding`, and `conv1d` architectures are now registered through it, `create_ann()` dispatches on `rule.architecture` and falls back to the historical auto-selection when it is unset (so existing configs are unaffected), and an unknown architecture now fails loudly with a hint that the providing module may not be loaded</li><li>**fasttext_embed sequence output**: The `fasttext_embed` provider gains `output_mode = &quot;sequence&quot;`, emitting the first `max_words` word vectors flattened word-major and zero-padded to `max_words * channels`, so custom architectures can learn their own pooling instead of receiving a pre-pooled vector. An optional `word_selection = &quot;sif&quot;` fills the sequence with the most distinctive (highest SIF weight) words from anywhere in the message rather than the leading ones; the default stays `prefix`</li><li>**Multi-head attention pooling**: A new `attn_pool` KANN operator performs multi-head dot-product attention pooling over a zero-padded sequence of word vectors with learned query vectors, masking all-zero padding positions out of the softmax. Exposed as `rspamd_kann.layer.attn_pool(node, n_words[, n_heads])`, it converges on a word-order-invariant needle-in-haystack task that a flat dense net cannot solve, and the operator is appended to preserve model serialization compatibility</li><li>**KANN slice and concat transforms**: `rspamd_kann.transform.slice(node, axis, start, end)` (0-based, end exclusive) and `rspamd_kann.transform.concat(axis, node1, node2, ...)` expose the already-serialized `kad_slice` / `kad_concat_array` graph operators to Lua, making split/bypass/merge topologies — e.g. routing parts of a fused input vector through different sub-networks for attention pooling with late fusion — buildable from Lua</li></ul><h3>Fixed</h3><ul><li>**DNS resolver startup crash (4.1.0 regression)**: A nameserver that failed to resolve at config time was turned into a zero-address pending-resolve upstream and then dereferenced as NULL in `rspamd_dns_server_init`, crashing the worker with SIGSEGV at startup. Resolver nameservers are consumed synchronously and can never be promoted asynchronously, so they are no longer deferred, with a NULL guard added as defense in depth ([#6096](https://github.com/rspamd/rspamd/issues/6096))</li><li>**Milter QUARANTINE with custom reply (3.10.0 regression)**: The QUARANTINE command was emitted only inside the branch that synthesises a default quarantine reason, so a caller-supplied SMTP message (e.g. `task:set_pre_result(&apos;quarantine&apos;, &apos;reason&apos;)`) suppressed the command entirely and the message was accepted instead of quarantined. The supplied message now becomes the quarantine reason, matching the reject and tempfail branches; this affects both `METRIC_ACTION_QUARANTINE` and reject converted via `quarantine_on_reject` ([#6088](https://github.com/rspamd/rspamd/issues/6088))</li><li>**Coroutine thread-pool safety**: Async Lua libraries (DNS, Redis, TCP, HTTP, util) capture the running coroutine at a yield point and resume it later from a C completion callback, with nothing previously guaranteeing the resumed entry was still the captured one. Each pooled thread now carries an explicit lifecycle and generation counter, and the entries are refcounted, so a double-fired event, a completion racing task teardown, or an entry recycled into another task either resumes the correct live coroutine or becomes a logged no-op — instead of dereferencing freed memory ([#6104](https://github.com/rspamd/rspamd/pull/6104))</li><li>**lua_worker subprocess deadlock**: A function run via `worker:spawn_process` that returned `nil` (or any non-string value) logged an error but wrote nothing to the result pipe, so the parent waited forever for a reply while the child blocked on the post-reply ack — deadlocking both processes and anything serialised behind them, notably the neural training lock. Invalid return values are now reported to the parent as a regular error reply, so `on_complete` fires and the caller can recover</li><li>**Neural training on dense embeddings**: Training on dense provider features (`fasttext_embed`, `text_hash`) with the historical `learning_rate = 0.01` could drive the net into tanh saturation and silently save a degenerate single-class model that classified every message the same way until the next retrain — roughly one weight-init in three on a real corpus. Dense-feature rules now use the funnel (embedding) architecture, whose layernorm fixes the conditioning; the learning-rate default is resolved by input type (0.001 for dense embeddings, 0.01 for symbol vectors, an explicit config value still wins); and a quality gate rejects a constant/single-class model so training retries on the next cycle with a different init</li><li>**Stranded trained ANNs**: A trained ANN could become unreachable to workers — `NEURAL_SPAM` / `NEURAL_HAM` stopped firing while the controller logged a version mismatch forever — because a stale, empty, high-version profile entry shadowed the live lower-version blob and, with no TTL, never expired. New versions are now seeded monotonically from the profile actually trained from, selection falls back to the next compatible profile with a live blob (with a throttled warning) when the chosen one is missing, and profile/blob entries get a TTL refreshed each cycle so an actively used ANN never expires out from under its entry ([#6089](https://github.com/rspamd/rspamd/pull/6089))</li><li>**mx_check loopback classification**: A domain whose MX resolves only to loopback is hosted on the scanning host itself (typically the host&apos;s own FQDN mapped to `127.0.0.1` in `/etc/hosts`), but it scored `MX_BOGON_ONLY` (+8.0) — the strongest &quot;not spam infrastructure&quot; signal treated as the strongest spam signal, penalising fully DMARC-aligned self-hosted mail. `127.0.0.0/8` and `::1/128` move from the bogon set to the local set, so such mail now emits `MX_LOCAL_ONLY` (3.0) ([#6101](https://github.com/rspamd/rspamd/issues/6101))</li><li>**Monitored random DNS prefixes**: `random_monitored` RBL checks built random labels from an alphabet including `-` and `_`, producing names like `_Q8...0-` or `-7d0...` that are not valid DNS labels (RFC 952/1123) and that authoritative DNSBL servers such as spfbl.net reject with SERVFAIL. The alphabet is restricted to alphanumerics, which always forms a valid label regardless of position while keeping ample entropy ([#6103](https://github.com/rspamd/rspamd/issues/6103))</li><li>**v3 multipart boundary case**: RFC 2046 boundaries are case-sensitive, but the v3 HTTP multipart callers used the boundary lowercased for MIME-client quirks, so requests with uppercase boundary characters failed to parse. The case-preserving `orig_boundary` is now used in `protocol.c`, `rspamd_proxy.c`, and `rspamdclient.c`</li><li>**/checkv3 on the controller**: The controller&apos;s HTTP path router never registered `/checkv3`, so a plain `rspamc --protocol-v3` — which defaults to the controller port 11334 on localhost — returned 404. The endpoint is now registered and routed to the existing scan handler, branching on `CMD_CHECK_V3` in both directions to mirror the proxy, with an auth posture matching `/check` and `/checkv2` ([#6083](https://github.com/rspamd/rspamd/pull/6083))</li><li>**Symcache timeout inflation**: A `saved_priority` initialised to `-1` split the first item of each pre/postfilter/idempotent phase off from its priority group and counted it individually, inflating the computed maximum symbols-cache timeout. It is now seeded from the first item&apos;s priority so items at the same priority group correctly ([#6094](https://github.com/rspamd/rspamd/pull/6094), [#6092](https://github.com/rspamd/rspamd/issues/6092))</li><li>**Query-embedded URLs with &apos;=&apos;**: A bare embedded URL is its own query parameter and can itself contain `=` (e.g. base64 padding in the path), but the query-embedded scan treated everything before the first `=` as a parameter key and discarded such URLs. The prefix is now treated as a key only when it has no URL structure characters (`:` or `/`); otherwise the whole parameter is scanned</li><li>**URLs with multiple &apos;@&apos; and backslashes**: URLs containing several `@` signs and backslashes were multiplied into many spurious URLs. Long legitimate conversations can accumulate such links, so the spurious expansion could drop mail and, with autotrain enabled, train the system badly; those URLs are no longer multiplied ([#6065](https://github.com/rspamd/rspamd/pull/6065))</li><li>**More CSS hiding via overflow/opacity/max-***: Phishing that dilutes visible content with hidden ham text using `max-width:0;max-height:0;overflow:hidden`, `opacity:0`, or `height:0` was missed — `max-*` and `overflow` were unparsed, `opacity` was parsed but discarded, and a copy-paste bug applied `height:0` to the block width. These properties are now parsed, a zero-dimension-with-`overflow:hidden`, low-opacity, or hidden-ancestor block is treated as invisible and propagated to descendants, and a child display value can no longer resurrect content hidden by an ancestor</li><li>**OpenSSL 4.0 build**: OpenSSL 4.0 made `ASN1_STRING` (and thus `ASN1_OCTET_STRING`) opaque, so direct access to its length/data fields no longer compiled; `ASN1_STRING_length()` / `ASN1_STRING_get0_data()` (available since OpenSSL 1.1.0 and LibreSSL 2.7) are used instead, and the legacy OpenSSL init calls are moved under the pre-1.1.0 guard to fix no-deprecated builds ([#6087](https://github.com/rspamd/rspamd/issues/6087))</li><li>**doctest 2.5.0 build**: `mime_string`&apos;s iterator is intrinsically const, so it is marked as such and the `const_iterator` reference is dropped, fixing a compile error where doctest 2.5.0 receives a const reference and cannot use a mutable iterator ([#6072](https://github.com/rspamd/rspamd/pull/6072))</li><li>**Bundled simdutf headers**: The bundled simdutf headers are now prioritised over system ones to avoid version skew ([#6082](https://github.com/rspamd/rspamd/pull/6082))</li></ul>]]></description>
      <category>patch</category>
    </item>
    <item>
      <title>Rspamd 4.1.0 - Major Release with Load-Aware Upstreams, MX Check Rework, Dynamic Composites, and Hardening</title>
      <link>https://docs.rspamd.com/changelog/4.1.0</link>
      <guid isPermaLink="false">https://docs.rspamd.com/changelog/4.1.0</guid>
      <pubDate>Fri, 05 Jun 2026 00:00:00 GMT</pubDate>
      <description><![CDATA[<h2>Rspamd 4.1.0 - Major Release with Load-Aware Upstreams, MX Check Rework, Dynamic Composites, and Hardening</h2><h3>Changed</h3><ul><li>**MX check rework**: `mx_check` replaces its single domain-keyed cache with a three-layer Redis design (`d:&lt;domain&gt;` / `m:&lt;mxhost&gt;` / `i:&lt;ip&gt;` under `&lt;key_prefix&gt;:`), so two domains sharing an MX host (every G-Suite/M365 tenant, every ESP customer) reuse the m- and i-layer entries and hit cache with zero new DNS or TCP work. Outcome symbols are finer-grained and `MX_NONE` now replaces the old `MX_NXDOMAIN`/`MX_MISSING`; the probe is split into clean connect-only and full SMTP-banner shapes with multi-line greeting support. **Operators should review their `mx_check` scores and any rules referencing the old symbol names** ([#6055](https://github.com/rspamd/rspamd/pull/6055), [#6032](https://github.com/rspamd/rspamd/issues/6032))</li><li>**Fuzzy SRV discovery by default**: The stock `rspamd.com` fuzzy rule now uses `service=fuzzy+rspamd.com` SRV-based discovery instead of a hardcoded round-robin host list, so backends and ports are managed entirely in DNS. The legacy `fuzzy1`/`fuzzy2` hostnames keep resolving to every live backend, so installs that pinned the old string are unaffected</li></ul><h3>Added</h3><ul><li>**Custom metadata for /checkv3**: A `headers` sub-object in the multipart metadata part is injected into the task request headers (so `task:get_request_header()` works for custom fields), and the full metadata object is exposed to Lua via `task:get_metadata()` / `task:get_metadata_field(key)`. Both paths travel in the multipart body, free of the 80KB HTTP header limit that v2 hits; `rspamc` gains a repeatable `--metadata-header KEY=VALUE` option ([#6074](https://github.com/rspamd/rspamd/pull/6074))</li><li>**Dynamic composites**: A reserved `dynamic` key in the `composites { ... }` block attaches a hot-reloadable map of composites (file, URL list, or signed map) using the same vocabulary as static composites. Reloads register new names with the symcache, materialise removed names as stubs, and swap an atomic generation so in-flight tasks keep their snapshot ([#6064](https://github.com/rspamd/rspamd/pull/6064))</li><li>**Bulk and regexp symbol lookups**: `task:has_symbol()` / `task:get_symbol()` accept a `{S1, ..., Sn}` table form, and new `task:has_symbol_regexp(re)` / `task:get_symbol_regexp(re)` match fired symbol names against an `rspamd_regexp` userdata</li><li>**Phase-specific TCP timeouts**: `rspamd_tcp.new` gains `connect_timeout` / `read_timeout` / `write_timeout` for independent per-phase budgets and an `on_error(err, conn)` callback that fires once for pre-connect failures (DNS, socket, connect refused/timeout, SSL handshake). Legacy single-`timeout` callers keep their existing deducted-budget contract unchanged ([#6034](https://github.com/rspamd/rspamd/pull/6034))</li><li>**Stalled-scan diagnostics**: On task timeout the log now includes a grouped summary of still-pending async events (DNS / Redis / Lua HTTP / fuzzy / TCP) annotated with the stalling rule and operation, plus the list of symbols that started but never finished — replacing the opaque &quot;forced processing&quot; line with an immediate picture of what hung the scan ([#5990](https://github.com/rspamd/rspamd/pull/5990))</li><li>**Load-aware upstream selection**: Upstreams now support Power of Two Choices selection, a per-upstream latency EWMA with configurable half-life, and linear slow start on revive to avoid thundering-herd flap loops. `RSPAMD_UPSTREAM_RANDOM` callers are transparently upgraded to P2C ([#6013](https://github.com/rspamd/rspamd/pull/6013))</li><li>**Per-target SRV upstreams**: Each SRV reply target now materialises its own `struct upstream` with its own error budget, weight, latency EWMA, and address list, so SRV weights are honoured and a single failing target no longer drains the whole cluster&apos;s budget ([#6030](https://github.com/rspamd/rspamd/pull/6030))</li><li>**Deferred DNS resolution**: A transient DNS failure at config time no longer drops an upstream and cascades into module init failures. Unresolvable hostnames are kept pending and retried by the async lazy-resolve machinery (with exponential backoff), so the daemon starts and recovers automatically without a restart ([#6008](https://github.com/rspamd/rspamd/pull/6008), [#6000](https://github.com/rspamd/rspamd/issues/6000))</li><li>**MX check classification and trust maps**: `mx_check` partitions resolved MX-target IPs into PUBLIC / LOCAL / BOGON (only PUBLIC is probed), adds `bad_mxs` (glob on hostnames) and `bad_ips` (radix on IPs) punishment maps with optional per-entry weight multipliers, per-source checks across envelope / reply-to / MIME-from, and `check_authorized` / `check_local` run-scope toggles ([#6039](https://github.com/rspamd/rspamd/pull/6039), [#6032](https://github.com/rspamd/rspamd/issues/6032))</li><li>**External-service anchor symbols**: Every external service is scheduled under a stable `&lt;RULE&gt;_CHECK` callback symbol so it is a predictable dependency target regardless of how the scan-result symbols are named, generalising the existing `VADE_CHECK` / `CLOUDMARK_CHECK` pattern</li><li>**Chain-aware URL redirector cache**: `url_redirector` gains a per-hop Redis cache with intermediate-hop injection, so shared intermediate links are reused across chains and resolved hops are made visible to downstream modules; the walk self-heals on partial cache misses and surfaces previously-silent lock/stale conditions ([#6014](https://github.com/rspamd/rspamd/pull/6014))</li><li>**Stealth fingerprint profiles**: `url_redirector` replaces its flat `default_ua` list with five coherent browser profiles (Chrome, Edge, Firefox, Safari), each bundling a User-Agent with the exact header set, values, and order that browser sends (including `sec-ch-ua` client hints where appropriate). One profile is picked per task and reused across every hop ([#6053](https://github.com/rspamd/rspamd/pull/6053))</li><li>**Glob redirector hosts**: `redirector_hosts_map` now accepts glob patterns (e.g. `*.bit.ly`, `*.t.co`); bare hostnames still match exactly, so existing maps are unaffected ([#6056](https://github.com/rspamd/rspamd/pull/6056))</li><li>**GET for selected redirector URLs**: `url_redirector` can issue GET (rather than HEAD) for an operator-defined list of URLs matched by regexp ([#6043](https://github.com/rspamd/rspamd/pull/6043))</li><li>**Insertion-ordered HTTP headers**: An opt-in `RSPAMD_HTTP_FLAG_ORDERED_HEADERS` emits headers in insertion order instead of hash order; `lua_http` accepts a list form (`{{&apos;name&apos;,&apos;value&apos;}, ...}`) to preserve order, used by the redirector stealth profiles</li><li>**Richer Elasticsearch logging**: The `elastic` module now logs Reply-To user/domain, received IPs, per-URL and CTA URL metadata via a new `collect_urls` block, and the forcing module name from `task:has_pre_result()` ([#6018](https://github.com/rspamd/rspamd/pull/6018))</li><li>**ClickHouse column presets**: Named `extra_columns` presets, including an initial outbound preset, can be selected without hand-rolling the schema ([#5983](https://github.com/rspamd/rspamd/pull/5983))</li><li>**New selectors**: `fuzzy_digest`, `fuzzy_shingles`, `authenticated`, and `received_count` ([#5981](https://github.com/rspamd/rspamd/pull/5981))</li><li>**HTML5 tag definitions**: 32 modern HTML5 tags (sectioning, media, text-level, interactive, forms, web components), notably `video`/`audio`/`source`/`track`/`picture`/`svg`, so their URLs and structure are visible to the parser; new tag IDs are appended so existing IDs stay stable</li><li>**DMARC report throttling**: `rspamadm dmarc_report` gains `-w`/`--batch-wait` to pause between batches (and stagger report generation), avoiding overload of the SMTP server and a weak resolver ([#5985](https://github.com/rspamd/rspamd/pull/5985))</li><li>**autolearnstats sorting**: `--sort-by &lt;col&gt;` and `--group` options for the `rspamadm autolearnstats` table output ([#6050](https://github.com/rspamd/rspamd/pull/6050))</li><li>**Feedback report parsers**: New `lua_feedback_parsers` lualib for parsing DSN (delivery status) and ARF (abuse) reports ([#5982](https://github.com/rspamd/rspamd/pull/5982))</li><li>**Structured custom-Lua loader**: `lua_extras` provides a two-phase loader for custom selectors, maps, and regexps under `lua.local.d/{maps,selectors,regexps}/`, resolving cross-kind dependencies (maps → selectors → regexps) so a selector can consume a map registered by an earlier kind ([#6020](https://github.com/rspamd/rspamd/pull/6020))</li><li>**eXpurgate scanner**: New `lua_scanners` engine for the eXpurgate anti-spam service ([#5755](https://github.com/rspamd/rspamd/pull/5755))</li><li>**Per-worker memory dumps**: New `rspamadm control memstat` command reports per-worker RSS, per-callsite mempool counters, Lua heap usage, and structured per-arena jemalloc stats, with `--short`, `--sort`, and per-section toggle flags ([#6016](https://github.com/rspamd/rspamd/pull/6016))</li><li>**Container-friendly baseline config**: The baseline pidfile and logging type/filename are now env-overridable (`RSPAMD_PIDFILE`, `RSPAMD_LOG_TYPE`, `RSPAMD_LOG_FILE`); an empty pidfile disables it (useful as PID 1), and `RSPAMD_LOG_TYPE=console` logs to stdout. Stock installs render the previous defaults bit-for-bit ([#6067](https://github.com/rspamd/rspamd/pull/6067))</li><li>**Auto-loaded fasttext model**: When no `fasttext_model` is configured, the shipped `$SHAREDIR/languages/fasttext_model.ftz` is loaded if present, so images bundling the model can drop the explicit override; stock installs without the file behave exactly as before ([#6067](https://github.com/rspamd/rspamd/pull/6067))</li><li>**Fixed-point float formatting**: `fpconv` gains `%.Nf` fixed-point formatting with correct rounding and carry handling ([#6061](https://github.com/rspamd/rspamd/pull/6061))</li></ul><h3>Fixed</h3><ul><li>**Composite visibility from postfilters**: Composites depending only on ordinary filter-stage rules were wrongly deferred to the post-composites stage because nearly every virtual/callback symbol carries `NOSTAT`; a composite is now deferred only when a dependency actually resolves to the postfilter stage, restoring `task:get_groups()`/`get_symbols()` visibility from postfilters</li><li>**Ratelimit multi-bucket tracking**: A selector rule with several buckets (e.g. `200/1h` plus `30/1m`) keyed every bucket on the selector value alone, so only the last bucket was tracked and the other limits were silently ignored; each bucket now gets a distinct Redis key ([#6076](https://github.com/rspamd/rspamd/pull/6076), [#6059](https://github.com/rspamd/rspamd/issues/6059))</li><li>**Verbatim href preserved**: `url:get_raw()` returned the partially percent-decoded scratch buffer for HTML URLs; `url-&gt;raw` now points at a mempool-owned copy of the verbatim trimmed href ([#5986](https://github.com/rspamd/rspamd/issues/5986))</li><li>**Mailto canonicalisation**: A bare email in text/HTML and the same address inside an explicit `mailto:` URL were extracted as two separate emails; both injection sites now canonicalise to the slash-less `mailto:` form (RFC 6068) so dedup collapses them</li><li>**Long userinfo URLs preserved**: A blanket length REJECT silently dropped URLs whose userinfo exceeded 2KB — exactly the `https://legit.com   @evil.com/...` userinfo-obfuscation phishing pattern; the cap is raised to 16KiB and the URL is flagged obscured as soon as userinfo crosses 64 bytes</li><li>**Naked-domain false positives**: `url_suspect` now requires a TLD of at least 3 chars for `word_dot` naked-domain matches, so prose like &quot;pale blue dot so insignificant&quot; no longer normalises to `blue.so`; explicit-protocol patterns still match two-char TLDs</li><li>**Deterministic ARC header order**: `lua_mime.modify_headers` honoured its `order` list but serialised in hash order; ARC sets are now emitted in the conventional ARC-Seal / ARC-Message-Signature / ARC-Authentication-Results layout, which some validators (e.g. O365) require ([#6052](https://github.com/rspamd/rspamd/pull/6052), [#6045](https://github.com/rspamd/rspamd/issues/6045))</li><li>**DKIM permfail mapping**: An invalid DKIM record now maps to `dkim=permerror` in `Authentication-Results` instead of falling through to `dkim=none` ([#6028](https://github.com/rspamd/rspamd/pull/6028), [#5957](https://github.com/rspamd/rspamd/issues/5957))</li><li>**EAI Message-ID handling**: The `INVALID_MSGID` rule now honours `mime_utf8`, and the `enable_mime_utf8` option spelling is registered as an alias so it actually takes effect, fixing false positives on valid SMTPUTF8 Message-IDs (RFC 6532) ([#6011](https://github.com/rspamd/rspamd/pull/6011), [#6007](https://github.com/rspamd/rspamd/issues/6007))</li><li>**Fuzzy storage peer pipe**: Partial peer-pipe writes were retried from byte 0, shoving garbage into the pipe; writes now resume at the sent offset, and pending requests are drained on worker shutdown instead of leaking</li><li>**Fuzzy dynamic-ban leak**: Re-applying an already-present ban prefix orphaned a freshly allocated ban struct in the long-lived mempool on every refresh; the prefix is now looked up first and mutated in place on a hit</li><li>**Fuzzy persistent-TCP leak**: Per-frame `cmd_session` state (extensions buffer, key refs) leaked on every frame after the first on a persistent TCP connection; per-command state caching is dropped so each frame starts clean ([#6001](https://github.com/rspamd/rspamd/issues/6001))</li><li>**Allowed fuzzy clients on TCP**: Allowed clients are no longer blocked on the TCP path ([#5992](https://github.com/rspamd/rspamd/pull/5992))</li><li>**Neural ANN survival**: A trained ANN is now preserved across symbol-list drift and symcache-driven profile rotation; the profile digest is stabilised under `disable_symbols_input` (keyed on the providers config rather than the unrelated symbol catalogue), and training is retargeted to the newest profile so inference no longer goes dark for weeks until a fresh model trains ([#6041](https://github.com/rspamd/rspamd/pull/6041))</li><li>**Inline /checkv3 settings**: Inline `metadata.settings` on `/checkv3` were stashed directly on the task and skipped the apply pipeline; they now run through the same `settings.lua` apply path as v2, so action thresholds, symbols, subject, variables, and header edits take effect ([#5999](https://github.com/rspamd/rspamd/issues/5999))</li><li>**/checkv3 request headers**: Arbitrary client HTTP headers are now registered so `task:get_request_header()` works under v3, restoring v2 behaviour ([#5998](https://github.com/rspamd/rspamd/issues/5998))</li><li>**Token-bucket recovery**: A flapping upstream&apos;s token bucket drained monotonically toward zero and never recovered; lazy time-based refill restores tokens over wall time so a recovered upstream re-enters selection</li><li>**get_random termination**: `rspamd_upstream_get_random` looped forever when the only alive candidate matched the `except` argument; the empty and single-survivor cases are now front-gated</li><li>**Lua TCP leak**: A connection that read without writing leaked; the leak is closed ([#6048](https://github.com/rspamd/rspamd/pull/6048))</li><li>**Redis master under Sentinel**: Standalone `rspamadm` tools never resolved the current Redis master, round-robining writes that failed `READONLY` on replicas; a new one-shot `lua_redis.prepare_redis_setup` resolves the master (and loads scripts) for tools like `dmarc_report` ([#6015](https://github.com/rspamd/rspamd/pull/6015), [#6009](https://github.com/rspamd/rspamd/issues/6009))</li><li>**Elastic overflow guard**: The row-limit overflow guard called a non-existent `lua_util.newdeque()`; it now resets the buffer via the local `Queue` class</li><li>**DMARC report on PUC Lua**: The connect timestamp is floored before `os.date`, which PUC-Rio Lua rejects for non-integer floats (only seen on the Fedora build)</li><li>**Greylist timeout separation**: The greylisting period (5 min) was being picked up by `lua_redis` as the Redis connection timeout; a separate `redis_timeout` (default 1.0s) is introduced and propagated into nested `redis{}` blocks ([#5977](https://github.com/rspamd/rspamd/pull/5977))</li><li>**rspamadm vault output**: `rspamadm vault list` produced empty output for large vaults because the payload passed through a format-string logger; it is now written to stdout directly via `io.write` ([#6006](https://github.com/rspamd/rspamd/pull/6006), [#6005](https://github.com/rspamd/rspamd/issues/6005))</li><li>**Regexp capture groups**: An empty capture group in the middle of a match no longer discards all following groups (PCRE1 and PCRE2); results are truncated at the last non-empty group instead ([#5974](https://github.com/rspamd/rspamd/pull/5974), [#5973](https://github.com/rspamd/rspamd/issues/5973))</li><li>**x-binaryenc charset**: ICU conversion is skipped for the synthetic `x-binaryenc` charset across all detection paths, silencing the spurious &quot;cannot open converter&quot; warning and correctly marking the part as raw binary ([#5984](https://github.com/rspamd/rspamd/pull/5984))</li><li>**Timeout sanity check**: `configtest` now warns when `task_timeout` is less than a symcache symbol timeout, including per-worker overrides ([#5978](https://github.com/rspamd/rspamd/pull/5978))</li><li>**libc++ builds**: Use `string_view::data()` for pointer access where libc++ returns a wrapped iterator from `begin()`, fixing builds with libc++ 22 on FreeBSD ([#5969](https://github.com/rspamd/rspamd/issues/5969))</li><li>**In-place header rewrites**: `mime_headers`/`mime_encoding` now recompute lengths after in-place strip/trim rewrites, so stale trailing bytes are no longer pulled into the Message-ID or normalised charset name, and large-buffer offsets use `goffset` to avoid 32-bit truncation</li><li>**rfc2047 decode**: A failed base64 encoded-word no longer leaves uninitialised bytes in the decoded header value; the token length is reset to the saved offset on the failure path</li></ul><h3>Security</h3><ul><li>**S/MIME NULL deref**: An S/MIME signed message wrapping a zero-length `pkcs7-data` OCTET STRING crashed the parser on the first byte check; the empty inner recursion is skipped and a defensive guard is added against NULL/empty buffers</li><li>**S/MIME recursion bound (DoS)**: Deeply nested `application/pkcs7-mime` layers re-entered the parser without incrementing the nesting counter, recursing to a depth bounded only by message size and exhausting the worker stack; the S/MIME re-entry is now accounted against `max_nested` and the CMS/PKCS7/BIO objects are freed on the error path</li><li>**MIME parser guards**: Additional defensive guards against NULL dereference (Content-Type iteration, malformed PKCS7 signed-data) and a leak of the recursive parser context on the early error-return path, plus a corrected `begin-base64` UUE prefix offset</li><li>**Nested-query URL DoS**: A crafted message with a few levels of percent-escaped nested query URLs exhausted the multipattern hyperscan scratch pool and aborted the worker via assertion; the scratch budget is enlarged, the query-nesting cap is restored to a fixed functional limit, and scratch exhaustion is made non-fatal ([#6066](https://github.com/rspamd/rspamd/pull/6066))</li><li>**Archive parser hardening**: RAR (v4/v5), ZIP, and 7-zip parsers are hardened against malformed attachments — re-validated filename lengths, guarded section/digest/bit reads, clamped extra-field advances, a fixed EOCD minimum, widened offset arithmetic against 32-bit wrap, and corrected 7-zip varint decoding (uninitialised value and an undefined-shift fix)</li><li>**Image linking guard**: Content-Id image linking is guarded against a NULL decoded header</li><li>**CSS out-of-bounds read**: The CSS ident-escape scanner could read one byte past a tightly-sized style-attribute buffer when a token ended in backslash plus a hex digit; the increment is now bounds-gated</li><li>**Header lookahead over-read**: `rspamd_string_find_eoh` peeked `p[1]` guarded only by `p &lt; end`, reading one byte past the buffer on input ending in `\r\r`; it now checks `p + 1 &lt; end`</li><li>**SPF over-read**: A TXT record of exactly `spf2.` advanced past one unvalidated byte and read past the string end; the parser now advances only past the validated prefix with short-circuiting checks</li><li>**DNS label overrun**: `rdns_parse_labels` never verified that label data fits within the packet, so a reply declaring more bytes than remained made the second-pass `memcpy` read past the (exactly-sized, on TCP) buffer; both plain and compressed labels are now validated, with an off-by-one fix in offset decompression</li><li>**HTML entity overflow**: In-place HTML entity decoding assumed the replacement is never longer than the source, which fails for short names expanding to multiple codepoints (`nGt`, `nLt`, `nvap`); the replacement is now bounds-checked against the remaining buffer</li><li>**Empty-host URL over-read**: `rspamd_url_maybe_regenerate_from_ip` could read `host[-1]` on an all-dots or zero-length-after-decode host; the trailing-dot loop condition is reordered and host length is re-checked after decoding</li><li>**Fuzzy network input hardening**: Three defensive fixes on user-controlled UDP/TCP paths — reset `msg_namelen` before every `recvmsg` to avoid parsing stale stack bytes, validate the reconstructed 14-bit TCP frame length before use, and clamp `n_extra_flags` before the fixed-size reply `memcpy`</li><li>**libucl upstream fixes**: Ported security fixes from libucl — msgpack negative fixint and unaligned-access fixes, a key-length validation, a nesting-depth limit, parser bounds checks, and a NULL guard in schema validators</li></ul>]]></description>
      <category>major</category>
    </item>
    <item>
      <title>Rspamd 4.0.1 - Patch Release with Layered Settings Merge, Fuzzy Dynamic Blocks, and Critical Bug Fixes</title>
      <link>https://docs.rspamd.com/changelog/4.0.1</link>
      <guid isPermaLink="false">https://docs.rspamd.com/changelog/4.0.1</guid>
      <pubDate>Sun, 05 Apr 2026 00:00:00 GMT</pubDate>
      <description><![CDATA[<h2>Rspamd 4.0.1 - Patch Release with Layered Settings Merge, Fuzzy Dynamic Blocks, and Critical Bug Fixes</h2><h3>Added</h3><ul><li>**Layered settings merge**: Collect-then-merge flow replaces first-match-wins; layers are merged with per-field semantics (actions/scores override by higher layer, symbols union with conflict resolution); `force_actions` and `force_symbols` provide explicit override when layers conflict ([#5959](https://github.com/rspamd/rspamd/pull/5959))</li><li>**Weak dependencies in symcache**: New `disabled` status distinguishes &quot;disabled by settings&quot; from &quot;finished&quot;; hard deps cascade-disable dependents while weak deps let them proceed — seven plugins annotated with correct dependency classification ([#5959](https://github.com/rspamd/rspamd/pull/5959))</li><li>**Fuzzy dynamic block API**: `worker:block_fuzzy_client(addr, prefix_len[, expire_ts[, reason]])` Lua method for runtime IP/CIDR blocking in fuzzy storage without config changes or restarts; custom response codes — 403 for ratelimits vs 503 for bans; `ratelimit_whitelist` check exposed to Lua ([#5962](https://github.com/rspamd/rspamd/pull/5962))</li></ul><h3>Fixed</h3><ul><li>**Proxy milter fd leak**: Original fd was not closed after milter `dup()`, leaking one fd per milter connection and causing unbounded `CLOSE_WAIT` accumulation in production (regression in 4.0.0)</li><li>**Proxy self-scan task timeout**: Self-scan tasks incorrectly used the upstream wire timeout (e.g. 120s) instead of `task_timeout` (8s default), masking hung tasks</li><li>**ARC AAR header parsing**: Replace naive semicolon split with LPeg grammar that respects RFC 8601 comments `(...)` and quoted strings — fixes `cv=fail` on multi-hop ARC chains where `i=N` appeared inside comments ([#5963](https://github.com/rspamd/rspamd/issues/5963), [#5966](https://github.com/rspamd/rspamd/pull/5966))</li><li>**Dynamic ban expiry**: Fix `ev_now()` usage for correct monotonic time in dynamic block expiry</li><li>**Settings flow**: Fix dependency ordering in pre/postfilters and settings apply phase</li><li>**Redis backend build**: Add missing `#include &lt;memory&gt;` in `redis_backend.cxx` ([#5960](https://github.com/rspamd/rspamd/pull/5960))</li></ul>]]></description>
      <category>patch</category>
    </item>
    <item>
      <title>Rspamd 4.0.0 - Major Release with checkv3 Protocol, Built-in Fasttext, Multi-Flag Fuzzy Hashes, and Ring Hash Consistent Hashing</title>
      <link>https://docs.rspamd.com/changelog/4.0.0</link>
      <guid isPermaLink="false">https://docs.rspamd.com/changelog/4.0.0</guid>
      <pubDate>Sat, 28 Mar 2026 00:00:00 GMT</pubDate>
      <description><![CDATA[<h2>Rspamd 4.0.0 - Major Release with checkv3 Protocol, Built-in Fasttext, Multi-Flag Fuzzy Hashes, and Ring Hash Consistent Hashing</h2><h3>Breaking Changes</h3><ul><li>**Bayes per-user resharding**: Jump Hash replaced with Ring Hash (Ketama) for consistent upstream hashing; per-user Bayes data on sharded Redis deployments will be on wrong shards after upgrade. Run `rspamadm statistics_dump migrate` before upgrading. Single-server deployments are unaffected. ([#5914](https://github.com/rspamd/rspamd/pull/5914), [4ea7504](https://github.com/rspamd/rspamd/commit/4ea750466))</li><li>**Content URLs included by default**: `include_content_urls` now defaults to `true`; URLs extracted from PDF and computed parts are returned by `task:get_urls()` by default, which may trigger new symbol hits on messages with PDF attachments. Restore old behavior with `include_content_urls = false` in `local.d/options.inc`. ([#5853](https://github.com/rspamd/rspamd/pull/5853))</li><li>**SSL worker option removed**: The `ssl = true` worker option has been removed; SSL is now auto-detected from bind socket flags. Remove `ssl = true` from worker configs and use the `ssl` suffix on bind lines instead. ([#5884](https://github.com/rspamd/rspamd/pull/5884))</li><li>**Proxy load balancing default changed**: Token bucket load balancing is now enabled by default for proxy upstreams, replacing simple round-robin. Remove the `token_bucket` key from proxy upstream config to restore round-robin behavior. ([#5874](https://github.com/rspamd/rspamd/pull/5874))</li><li>**SenderScore RBLs disabled by default**: `senderscore_reputation` is disabled by default as it requires a MyValidity account and was returning blocked results for all unregistered IPs. Users with registered accounts must explicitly re-enable the rule. ([#5907](https://github.com/rspamd/rspamd/pull/5907))</li><li>**DKIM unknown key handling per RFC**: Unknown and broken DKIM keys are now handled strictly per RFC, which may change DKIM results for messages with malformed keys. ([e9e6bac](https://github.com/rspamd/rspamd/commit/e9e6bac43))</li><li>**Suspicious TLDs now map-based**: The hardcoded suspicious TLD list has been replaced with `conf/maps.d/suspicious_tlds.inc`. Customize by creating `local.d/maps.d/suspicious_tlds.inc` (override) or `local.d/maps.d/suspicious_tlds.inc.local` (extend). ([614e68c](https://github.com/rspamd/rspamd/commit/614e68c8b))</li><li>**Neural module autolearn option renames**: Autolearn options in the neural module have been renamed to match RBL module naming conventions. Review custom neural configurations for use of old option names. ([#5835](https://github.com/rspamd/rspamd/pull/5835))</li><li>**libfasttext external dependency removed**: The external libfasttext C++ library has been replaced with a built-in mmap-based shim. The `ENABLE_FASTTEXT` cmake option is removed (always enabled). Packagers must remove the libfasttext build dependency. ([#5897](https://github.com/rspamd/rspamd/pull/5897))</li></ul><h3>Added</h3><ul><li>**Jinja2 configuration templates**: Configuration files are now preprocessed by the [Lupa Jinja2-compatible template engine](/configuration/templates) before UCL parsing. Environment variables prefixed with `RSPAMD_` are exposed as the `env` table in templates; modified delimiters (`{= =}` for expressions, `{% %}` for control structures) avoid conflicts with UCL syntax. New validation filters (`mandatory`, `require_int`, `require_number`, `require_bool`, `require_duration`, `require_json`, `fromjson`) abort startup with a clear error on invalid input, enabling container-ready configuration validation without shell entrypoint scripts. ([#5938](https://github.com/rspamd/rspamd/pull/5938), [#5941](https://github.com/rspamd/rspamd/pull/5941))</li><li>**checkv3 multipart protocol**: New `/checkv3` endpoint using `multipart/form-data` requests and `multipart/mixed` responses; metadata sent as structured JSON/msgpack instead of HTTP headers, per-part zstd compression, optional body part for rewritten messages, and zero-copy piecewise writev for responses. Use `rspamc --protocol-v3` or `rspamc --msgpack` to activate. ([#5880](https://github.com/rspamd/rspamd/pull/5880))</li><li>**Pluggable Hyperscan cache backend**: Hyperscan compilation and caching moved to an async Lua backend with Redis-based shared database support across workers and hosts. Async compilation prevents blocking the main event loop; self-healing cache auto-detects stale blobs and triggers recompile; small databases compiled in-memory without file caching. ([#5813](https://github.com/rspamd/rspamd/pull/5813), [#5952](https://github.com/rspamd/rspamd/pull/5952))</li><li>**Multi-flag fuzzy hashes**: A single fuzzy hash can now carry up to 8 flags simultaneously, allowing multiple rules to match the same digest with independent flag/value pairs. Redis update path rewritten in Lua with EVALSHA and NOSCRIPT recovery. Backward-compatible epoch 12 wire protocol with highest-value flag promoted to the primary slot. Fuzzy hashes now stored in Redis history. ([#5894](https://github.com/rspamd/rspamd/pull/5894), [#5860](https://github.com/rspamd/rspamd/pull/5860))</li><li>**HTML fuzzy phishing detection**: Dual-mode fuzzy matching — template matching and domain-sensitive matching. New `FUZZY_HTML_PHISHING` symbol fires when an HTML template matches but domains differ, detecting reused phishing templates with swapped links. ([173058061](https://github.com/rspamd/rspamd/commit/173058061))</li><li>**Built-in Fasttext shim**: External C++ libfasttext replaced with a zero-dependency mmap-based reader providing shared memory across workers via `MAP_SHARED`, eliminating per-worker heap copies and saving approximately 500MB–7GB RAM. No more C++ exception ABI issues. Existing `.bin`/`.ftz` models continue to work unchanged. Fasttext wired through maps infrastructure for hot-reloading. ([#5897](https://github.com/rspamd/rspamd/pull/5897), [#5909](https://github.com/rspamd/rspamd/pull/5909))</li><li>**Neural network and LLM embedding improvements**: External pretrained neural model support; LLM embedding providers with multi-model support, mean+max pooling, and SIF word weighting; multi-layer funnel architecture; language-based model and URL selection; expression-based autolearn for neural LLM providers; GPT module with configurable consensus thresholds, `context_augment` hook, and mempool variable storage. ([#5924](https://github.com/rspamd/rspamd/pull/5924), [#5903](https://github.com/rspamd/rspamd/pull/5903), [#5897](https://github.com/rspamd/rspamd/pull/5897), [#5835](https://github.com/rspamd/rspamd/pull/5835))</li><li>**HTTPS server support**: Workers can now serve HTTPS natively with SSL auto-detected from bind socket configuration, enabling secure WebUI and API without a reverse proxy. ([#5884](https://github.com/rspamd/rspamd/pull/5884), [d04b367](https://github.com/rspamd/rspamd/commit/d04b367db))</li><li>**Ring Hash (Ketama) consistent hashing**: Proper consistent hashing with virtual nodes ensures only ~1/n keys redistribute when an upstream fails, and keys return to their original upstream on recovery. ([4ea7504](https://github.com/rspamd/rspamd/commit/4ea750466))</li><li>**Token bucket proxy load balancing**: New load balancing algorithm for proxy upstreams with configurable `max_tokens`, `scale`, and `base_cost` parameters for better burst traffic handling. ([#5874](https://github.com/rspamd/rspamd/pull/5874))</li><li>**Multiclass Bayes support**: Classifiers now support arbitrary classes beyond binary spam/ham. WebUI learning interface updated for multi-class workflows. `/stat` and `/bayes/classifiers` endpoints extended with classifier metadata. `rspamadm statistics_dump` supports multi-class dump and restore. ([#5900](https://github.com/rspamd/rspamd/pull/5900), [#5893](https://github.com/rspamd/rspamd/pull/5893), [#5914](https://github.com/rspamd/rspamd/pull/5914))</li><li>**Structured metadata exporter**: New structured formatter for the metadata exporter module with zstd compression option and detected MIME types for attachments. ([#5890](https://github.com/rspamd/rspamd/pull/5890))</li><li>**UUID v7 per task**: Native UUID v7 generation per scanning task synced with the `Log-Tag` header and ClickHouse UUID v7 column support. ([#5890](https://github.com/rspamd/rspamd/pull/5890))</li><li>**ARC trusted_authserv_id**: Reuse upstream authentication results via trusted `Authentication-Results` headers from known authentication servers. ([506ef44](https://github.com/rspamd/rspamd/commit/506ef44b8))</li><li>**Legacy protocol milter headers**: Milter `add_headers` and `remove_headers` exposed in the RSPAMC/SPAMC text protocol with extended symbol info including descriptions and options, enabling Exim to access milter headers via `$spam_report`. ([#5948](https://github.com/rspamd/rspamd/pull/5948))</li><li>**rspamadm new subcommands**: `rspamadm autolearnstats` for autolearn statistics analysis; `rspamadm logstats` and `rspamadm mapstats` as rewrites of legacy Perl scripts; `rspamadm statistics_dump migrate` for Bayes shard migration. ([#5946](https://github.com/rspamd/rspamd/pull/5946), [#5885](https://github.com/rspamd/rspamd/pull/5885), [#5914](https://github.com/rspamd/rspamd/pull/5914))</li><li>**HTTP content negotiation**: Framework for content negotiation on API endpoints; `/stat` endpoint supports zstd-compressed responses. ([#5832](https://github.com/rspamd/rspamd/pull/5832))</li><li>**PDF improvements**: ASCII85 decode support, ligature substitution fix, object padding evasion defeat, and small objects no longer counted toward processing limits. ([73a37be](https://github.com/rspamd/rspamd/commit/73a37be63), [eb1acde](https://github.com/rspamd/rspamd/commit/eb1acde80), [2b91e5e](https://github.com/rspamd/rspamd/commit/2b91e5ef5), [1f02010](https://github.com/rspamd/rspamd/commit/1f020105e))</li><li>**Reply-To validity checks**: New header checks for `Reply-To` address validity. ([e95533f](https://github.com/rspamd/rspamd/commit/e95533f1f))</li></ul><h3>Fixed</h3><ul><li>**Fuzzy UDP use-after-free** (critical): Fixed use-after-free on ev_io watcher in fuzzy UDP sessions. ([4557166](https://github.com/rspamd/rspamd/commit/455716621))</li><li>**Fuzzy TCP CPU busy-loop**: Fixed CPU spin in fuzzy TCP client under certain error conditions. ([06dba44](https://github.com/rspamd/rspamd/commit/06dba4495))</li><li>**SPF address family flag inheritance**: Correct propagation of address family flags in SPF resolution. ([2a8643e](https://github.com/rspamd/rspamd/commit/2a8643e5e))</li><li>**DKIM RSA signing memory leak**: Fixed memory leak in RSA path of DKIM signing. ([9608160](https://github.com/rspamd/rspamd/commit/9608160b1))</li><li>**RHEL/CentOS 10 SHA-1 DKIM policy bypass**: Fixed crypto-policy bypass for SHA-1 DKIM signatures on RHEL/CentOS 10. ([7a38a8e](https://github.com/rspamd/rspamd/commit/7a38a8e33))</li><li>**Ratelimit compatibility with old records**: Fixed backward compatibility with legacy ratelimit bucket records. ([#5842](https://github.com/rspamd/rspamd/pull/5842))</li><li>**Weighted round-robin not respecting weights**: Fixed upstream selection ignoring configured weights. ([f563e25](https://github.com/rspamd/rspamd/commit/f563e25a0))</li><li>**SVG misdetection**: Fixed incorrect HTML detection for messages with embedded SVG content. ([170c4c5](https://github.com/rspamd/rspamd/commit/170c4c5d6))</li><li>**Hyperscan use-after-free on config reload**: Multiple use-after-free issues in Hyperscan cache handling during live configuration reload resolved. ([#5813](https://github.com/rspamd/rspamd/pull/5813))</li><li>**Jemalloc tuning**: Jemalloc tuned for Rspamd&apos;s single-threaded multi-process architecture, reducing memory overhead. ([#5949](https://github.com/rspamd/rspamd/pull/5949))</li></ul><h3>Improved</h3><ul><li>**Consistent hash distribution**: Ring Hash with virtual nodes provides true minimal disruption on upstream failure and guarantees key return to original upstream on recovery, replacing the previous Jump Hash algorithm.</li><li>**Hyperscan async compilation**: Compilation no longer blocks the main event loop; self-healing blob detection ensures cache correctness after Hyperscan version changes.</li><li>**Fasttext memory efficiency**: Built-in shim shares model data across all worker processes via shared memory, eliminating 500MB–7GB of duplicate heap allocations typical in multi-worker deployments.</li><li>**Fuzzy hash expressiveness**: Multi-flag support allows a single stored digest to satisfy multiple independent rule checks simultaneously without duplication in storage.</li></ul>]]></description>
      <category>major</category>
    </item>
    <item>
      <title>Rspamd 3.14.3 - Patch Release with PDF Text Extraction, Task Registry, and ClickHouse Extensibility</title>
      <link>https://docs.rspamd.com/changelog/3.14.3</link>
      <guid isPermaLink="false">https://docs.rspamd.com/changelog/3.14.3</guid>
      <pubDate>Thu, 08 Jan 2026 00:00:00 GMT</pubDate>
      <description><![CDATA[<h2>Rspamd 3.14.3 - Patch Release with PDF Text Extraction, Task Registry, and ClickHouse Extensibility</h2><h3>Added</h3><ul><li>**PDF text extraction**: Extract text from PDF attachments for content analysis with text quality filtering, FlateDecode and ASCIIHexDecode filter support, UTF-16 detection and conversion, ligature support for Standard and MacRoman encodings, and new `rspamadm mime -r` flag for raw extraction ([#5762](https://github.com/rspamd/rspamd/pull/5762))</li><li>**Task registry for Lua**: New task registry prevents use-after-free bugs in async Lua callbacks using counter-based keys instead of raw pointers for safe validation ([#5803](https://github.com/rspamd/rspamd/pull/5803))</li><li>**ClickHouse extra tables API**: Plugins can dynamically register custom ClickHouse tables via `rspamd_plugins[&apos;clickhouse&apos;].register_extra_table()` with per-table schemas, row callbacks, and independent retention settings ([#5810](https://github.com/rspamd/rspamd/pull/5810))</li><li>**WebUI error log**: New error log modal tracking last 50 API errors with unseen error counter badge, copy-to-clipboard support with HTTP fallback, and color-coded error types with responsive column hiding ([#5821](https://github.com/rspamd/rspamd/pull/5821))</li></ul><h3>Fixed</h3><ul><li>**Neural symbol flags**: Include symbols with no flags by default instead of excluding them</li><li>**Symcache FINE propagation**: Make FINE propagation deterministic ([#5825](https://github.com/rspamd/rspamd/issues/5825))</li><li>**URL numeric IP**: Prevent false positives from numeric IP regeneration in mailto URLs ([#5823](https://github.com/rspamd/rspamd/issues/5823))</li><li>**Settings selector**: Allow spaces in selector regexps</li><li>**Thai language**: Prevent R_MIXED_CHARSET false positives by marking Thai as having diacritics ([#5817](https://github.com/rspamd/rspamd/pull/5817), [#5799](https://github.com/rspamd/rspamd/issues/5799))</li><li>**GPT plugin**: Improved output format instructions for more reliable responses ([#5815](https://github.com/rspamd/rspamd/pull/5815), [#5670](https://github.com/rspamd/rspamd/issues/5670))</li><li>**io_uring HTTP**: Handle connection errors properly in HTTP client backend</li><li>**MIME Lua stack**: Restore Lua stack properly in second-pass detection</li><li>**Redis stats**: Add null checks for task in callbacks</li><li>**Lua 5.4 compatibility**: Fixes in ClickHouse and Elastic plugins ([#5774](https://github.com/rspamd/rspamd/pull/5774))</li><li>**Task lifetime crashes**: Fix potential crashes when Redis is unavailable longer than task lifetime ([#5803](https://github.com/rspamd/rspamd/pull/5803))</li></ul><h3>Improved</h3><ul><li>**replxx build**: Fix build with LLVM 21+</li><li>**macOS build**: Add Homebrew LLVM libc++ library path</li><li>**fmt library**: Update to version 12.1.0</li><li>**SDK headers**: Avoid SDK headers in include path when package ROOT is specified</li></ul>]]></description>
      <category>patch</category>
    </item>
    <item>
      <title>Rspamd 3.14.2 - Patch Release with Metadata Exporter Enhancements and DMARC RUA Validation</title>
      <link>https://docs.rspamd.com/changelog/3.14.2</link>
      <guid isPermaLink="false">https://docs.rspamd.com/changelog/3.14.2</guid>
      <pubDate>Wed, 10 Dec 2025 00:00:00 GMT</pubDate>
      <description><![CDATA[<h2>Rspamd 3.14.2 - Patch Release with Metadata Exporter Enhancements and DMARC RUA Validation</h2><h3>Added</h3><ul><li>**Metadata Exporter Formatters**: New formatters `multipart`, `msgpack`, and `json_with_message` for better message content handling including binary support and multipart uploads</li><li>**DMARC RUA Validation**: New `rspamadm dmarc_report --recheck-rua` flag to re-validate cached report addresses against exclusion maps (useful with RBLs)</li><li>**Selective AR Header Removal**: New `remove_ar_from` setting in milter_headers to selectively remove Authentication-Results headers from specific domains</li></ul><h3>Improved</h3><ul><li>**Metadata Exporter Docs**: Added comprehensive example for handling multipart metadata exports with Python/aiohttp</li></ul><h3>Deprecated</h3><ul><li>**Metadata Exporter**: `meta_headers` option is deprecated; use `multipart` or `msgpack` formatters instead</li></ul>]]></description>
      <category>patch</category>
    </item>
    <item>
      <title>Rspamd 3.14.1 - Minor Release with Composites Optimization, URL Deep Processing, and lua_shape Migration</title>
      <link>https://docs.rspamd.com/changelog/3.14.1</link>
      <guid isPermaLink="false">https://docs.rspamd.com/changelog/3.14.1</guid>
      <pubDate>Mon, 01 Dec 2025 00:00:00 GMT</pubDate>
      <description><![CDATA[<h2>Rspamd 3.14.1 - Minor Release with Composites Optimization, URL Deep Processing, and lua_shape Migration</h2><h3>Added</h3><ul><li>**Composites optimization**: Inverted index with bloom filter for fast negative symbol lookups, precomputed atom types, and composites statistics with control protocol command ([#5764](https://github.com/rspamd/rspamd/pull/5764))</li><li>**Multimap combinators**: Support for combinator option in multimap selector rules for flexible matching logic ([#5766](https://github.com/rspamd/rspamd/pull/5766))</li><li>**SPF flattening tool**: New rspamadm utility for SPF record flattening with macro preservation ([#5757](https://github.com/rspamd/rspamd/pull/5757))</li><li>**URL deep processing**: Architecture for C-to-Lua URL filter consultation with async HTML URL processing ([#5748](https://github.com/rspamd/rspamd/pull/5748))</li><li>**Obfuscated URL detection**: Enhanced url_suspect plugin with rspamd_util.decode_html_entities for detecting obfuscated URLs ([#5761](https://github.com/rspamd/rspamd/pull/5761))</li><li>**lua_shape validation**: New validation library replacing tableshape with T.callable() type and callable defaults support ([#5754](https://github.com/rspamd/rspamd/pull/5754))</li><li>**Whitelist symbol flags**: Auto-mark whitelist symbols with SYMBOL_TYPE_FINE flag for better scoring granularity</li></ul><h3>Fixed</h3><ul><li>**url_suspect false positives**: Fix plugin causing massive false positives with high URL volume messages ([#5758](https://github.com/rspamd/rspamd/pull/5758))</li><li>**Network chunking loop**: Prevent infinite loop in split_networks_into_chunks() function ([#5763](https://github.com/rspamd/rspamd/pull/5763))</li><li>**Memory leak**: Fix leak in custom tokenizer result handling</li><li>**lua_shape compatibility**: Multiple fixes for transform logic, registry resolution, error safety, and tableshape compatibility ([#5754](https://github.com/rspamd/rspamd/pull/5754))</li><li>**Composites inverted index**: Fix group matchers handling and improve atom polarity detection ([#5764](https://github.com/rspamd/rspamd/pull/5764))</li><li>**Lua composites**: Copy expression string to memory pool to prevent use-after-free ([#5764](https://github.com/rspamd/rspamd/pull/5764))</li><li>**D3 libraries**: Update with bug fixes and validation improvements ([#5765](https://github.com/rspamd/rspamd/pull/5765))</li><li>**Settings processing**: Keep groups_*/symbols_* fields in settings for runtime processing</li><li>**Redirect URL encoding**: Properly encode URLs with unencoded spaces and special characters ([#5748](https://github.com/rspamd/rspamd/pull/5748))</li><li>**WebUI hover**: Restore hover colors for symbols and fix hover behavior outside status tables ([#5741](https://github.com/rspamd/rspamd/pull/5741), [#5742](https://github.com/rspamd/rspamd/pull/5742))</li><li>**External relay**: Fix mixins and confighelp for external_relay module ([#5754](https://github.com/rspamd/rspamd/pull/5754))</li></ul><h3>Improved</h3><ul><li>**url_suspect performance**: Optimize plugin for high URL volume messages with better deduplication ([#5758](https://github.com/rspamd/rspamd/pull/5758))</li><li>**tableshape migration**: Complete migration of all plugins and libraries from tableshape to lua_shape ([#5754](https://github.com/rspamd/rspamd/pull/5754))</li><li>**Configuration simplification**: Remove use_*_map flags and simplify URL processing configuration ([#5748](https://github.com/rspamd/rspamd/pull/5748))</li><li>**Whitelist maps**: Use contemporary API for maps in whitelist module ([#5746](https://github.com/rspamd/rspamd/pull/5746))</li><li>**WebUI symbols**: Improved hover colors and behavior for symbols display ([#5760](https://github.com/rspamd/rspamd/pull/5760))</li><li>**Plugins registry**: Centralized plugins registry with reworked mixins and documentation ([#5754](https://github.com/rspamd/rspamd/pull/5754))</li></ul>]]></description>
      <category>minor</category>
    </item>
    <item>
      <title>Rspamd 3.14.0 - Major Release with HTML Fuzzy Hashing, TCP Fuzzy Protocol, and Enhanced URL Processing</title>
      <link>https://docs.rspamd.com/changelog/3.14.0</link>
      <guid isPermaLink="false">https://docs.rspamd.com/changelog/3.14.0</guid>
      <pubDate>Mon, 10 Nov 2025 00:00:00 GMT</pubDate>
      <description><![CDATA[<h2>Rspamd 3.14.0 - Major Release with HTML Fuzzy Hashing, TCP Fuzzy Protocol, and Enhanced URL Processing</h2><h3>Added</h3><ul><li>**HTML fuzzy hashing**: Structural similarity matching for HTML content with per-rule text_hashes toggle and dedicated shingles generation ([#5661](https://github.com/rspamd/rspamd/pull/5661), [#5720](https://github.com/rspamd/rspamd/pull/5720))</li><li>**Fuzzy TCP protocol**: Full TCP support in fuzzy storage and check with auto-switch, connection management, and proper framing ([#5669](https://github.com/rspamd/rspamd/pull/5669))</li><li>**CTA URL extraction**: New task:get_cta_urls() API and dedicated CTA module for proper call-to-action domain extraction ([#5732](https://github.com/rspamd/rspamd/pull/5732))</li><li>**Web search context**: LLM plugin integration with search API for domain context enrichment with Redis caching ([#5732](https://github.com/rspamd/rspamd/pull/5732))</li><li>**HTML URL rewriting**: Infrastructure for async HTML URL rewriting with Lua bindings and UTF-8 support ([#5676](https://github.com/rspamd/rspamd/pull/5676))</li><li>**Dark mode**: Full dark mode implementation in WebUI with theme toggle and auto detection ([#5725](https://github.com/rspamd/rspamd/pull/5725))</li><li>**Email aliases**: Advanced aliases resolution with loop detection for converging paths and expand_multiple mode ([#5655](https://github.com/rspamd/rspamd/pull/5655))</li><li>**ESMTP arguments**: Milter ESMTP argument parsing with Lua API access for per-recipient metadata ([#5663](https://github.com/rspamd/rspamd/pull/5663))</li><li>**URL hash method**: Exposed url:get_hash() method for efficient deduplication without string conversion overhead ([#5732](https://github.com/rspamd/rspamd/pull/5732))</li><li>**Postfix wizard**: Configwizard integration for automated Postfix setup using postconf utility ([#5667](https://github.com/rspamd/rspamd/pull/5667))</li><li>**BSD workflows**: Comprehensive GitHub Actions workflows for FreeBSD, NetBSD, and OpenBSD with Lua version selection ([#5726](https://github.com/rspamd/rspamd/pull/5726), [#5728](https://github.com/rspamd/rspamd/pull/5728), [#5729](https://github.com/rspamd/rspamd/pull/5729))</li><li>**Automated code review**: GitHub Actions workflow for Droid-powered code review with Rspamd-specific guidelines ([#5732](https://github.com/rspamd/rspamd/pull/5732))</li><li>**Multimap multisymbol**: Support for symbols with leading numerals in multimap plugin ([#5680](https://github.com/rspamd/rspamd/pull/5680))</li><li>**Remove headers array**: Support array of positions for milter remove_headers operations ([#5673](https://github.com/rspamd/rspamd/pull/5673))</li><li>**Client IP forwarding**: Proxy client IP preservation in message headers through chain ([#5671](https://github.com/rspamd/rspamd/pull/5671))</li><li>**Milter header support**: rspamc --mime support for milter.add_headers object format ([#5684](https://github.com/rspamd/rspamd/pull/5684))</li><li>**Public suffix automation**: Automatic synchronization of public suffix list via GitHub Actions ([#5718](https://github.com/rspamd/rspamd/pull/5718))</li><li>**Fuzzy migration utility**: Redis migration utility for fuzzy storage data ([#5692](https://github.com/rspamd/rspamd/pull/5692))</li><li>**Integration test suite**: Docker-based integration tests with ASAN, leak detection, and real corpus ([#5688](https://github.com/rspamd/rspamd/pull/5688))</li><li>**DMARC report headers**: Auto-Reply-To and Precedence headers to prevent out-of-office replies ([#5686](https://github.com/rspamd/rspamd/pull/5686))</li><li>**NetBSD memory support**: Memory usage tracking for NetBSD platform ([#5726](https://github.com/rspamd/rspamd/pull/5726))</li></ul><h3>Fixed</h3><ul><li>**DNS truncation**: Preserve req-&gt;pos during reply validation to prevent packet truncation on UDP-to-TCP retransmits ([#5739](https://github.com/rspamd/rspamd/pull/5739))</li><li>**DNS transaction ID**: Regenerate transaction ID before copying to TCP buffer to avoid collisions ([#5739](https://github.com/rspamd/rspamd/pull/5739))</li><li>**DMARC report batching**: Add batching and forced GC for Redis connections to prevent connection pool exhaustion ([#5737](https://github.com/rspamd/rspamd/pull/5737))</li><li>**Batch size validation**: Validate and normalize batch_size to prevent fractional indexing and loop errors ([#5737](https://github.com/rspamd/rspamd/pull/5737))</li><li>**Allocator mismatches**: Fix jemalloc/system malloc mixing in getline(), hiredis, and libucl to prevent crashes ([#5721](https://github.com/rspamd/rspamd/pull/5721), [#5724](https://github.com/rspamd/rspamd/pull/5724))</li><li>**Hyperscan version**: Use runtime version instead of compile-time for database validation and auto-recreate invalid cache files ([#5724](https://github.com/rspamd/rspamd/pull/5724))</li><li>**DNS round-robin**: Fix nameserver rotation from /etc/resolv.conf using ROUND_ROBIN instead of MASTER_SLAVE ([#5721](https://github.com/rspamd/rspamd/pull/5721))</li><li>**Memory leaks**: Fix leaks in fuzzy storage khash, upstream parsing, address parsing, OpenSSL providers, and UCL objects ([#5709](https://github.com/rspamd/rspamd/pull/5709))</li><li>**Fuzzy TCP bugs**: Fix double-release, timeout handling, buffer overflow, endianness mismatch, and race conditions ([#5669](https://github.com/rspamd/rspamd/pull/5669), [#5716](https://github.com/rspamd/rspamd/pull/5716))</li><li>**Shutdown tracking**: Keep srv events active during shutdown to track auxiliary processes via pipe notifications ([#5728](https://github.com/rspamd/rspamd/pull/5728))</li><li>**ARC signing**: Restore strict header ordering per RFC 8617 and add ed25519 key support ([#5684](https://github.com/rspamd/rspamd/pull/5684))</li><li>**Composite evaluation**: Implement two-phase evaluation for postfilter dependencies and fix symbol lookup ([#5681](https://github.com/rspamd/rspamd/pull/5681))</li><li>**URL extraction DoS**: Refactor to use hash-based deduplication with 50k URL limit to prevent string table exhaustion ([#5732](https://github.com/rspamd/rspamd/pull/5732))</li><li>**Bayes autolearn**: Allow skipping local/authenticated mail in default autolearn condition ([#5679](https://github.com/rspamd/rspamd/pull/5679))</li><li>**Bayes Redis discovery**: Improve Redis server discovery for Bayes storage ([#5714](https://github.com/rspamd/rspamd/pull/5714))</li><li>**ESMTP args parsing**: Robust per-recipient parsing in milter with safe cursor advance and refcount management ([#5663](https://github.com/rspamd/rspamd/pull/5663))</li><li>**HTML attribute offsets**: Correct offset calculation for URL rewriting in HTML attributes ([#5676](https://github.com/rspamd/rspamd/pull/5676))</li><li>**OpenBSD support**: Fix kinfo_proc member names and disable Hyperscan on OpenBSD ([#5729](https://github.com/rspamd/rspamd/pull/5729))</li><li>**FreeBSD packages**: Fix zstd package name and add IGNORE_OSVERSION for version mismatches ([#5729](https://github.com/rspamd/rspamd/pull/5729))</li><li>**NetBSD build**: Fix package installation with pkgin and correct dependency names ([#5726](https://github.com/rspamd/rspamd/pull/5726), [#5729](https://github.com/rspamd/rspamd/pull/5729))</li><li>**Bayes metadata leak**: Fix memory leak in stat metadata tokenization ([#5688](https://github.com/rspamd/rspamd/pull/5688))</li><li>**MIME anonymization**: Remove Authentication-Results and anonymize envelope-from in Received headers for LLM processing ([#5687](https://github.com/rspamd/rspamd/pull/5687))</li><li>**Multimap symbols**: Handle symbols with leading numerals in multimap ([#5680](https://github.com/rspamd/rspamd/pull/5680))</li><li>**Aliases validation**: Prevent creation of malformed email addresses in aliases module ([#5655](https://github.com/rspamd/rspamd/pull/5655))</li><li>**HTML fuzzy cache**: Fix cache key collision between text and HTML fuzzy hashes ([#5661](https://github.com/rspamd/rspamd/pull/5661))</li><li>**CSS normalization**: Fix CSS class normalization in HTML fuzzy token generation ([#5661](https://github.com/rspamd/rspamd/pull/5661))</li></ul><h3>Improved</h3><ul><li>**RBL configuration**: Refactored with new from selectors, content_urls checks, and lower_utf8 for hashed domains ([#5733](https://github.com/rspamd/rspamd/pull/5733))</li><li>**URL prioritization**: Prioritize CTA URLs in redirector and Lua helpers with proper phishing bonus preservation ([#5732](https://github.com/rspamd/rspamd/pull/5732))</li><li>**Fuzzy checks structure**: New structured checks configuration with backward-compatible legacy flags support ([#5720](https://github.com/rspamd/rspamd/pull/5720))</li><li>**Hash performance**: Replace GHashTable with khash in fuzzy_check and CTA URL extraction for better performance ([#5720](https://github.com/rspamd/rspamd/pull/5720), [#5732](https://github.com/rspamd/rspamd/pull/5732))</li><li>**WebUI icons**: Replace Glyphicons with FontAwesome SVG icons ([#5702](https://github.com/rspamd/rspamd/pull/5702))</li><li>**WebUI libraries**: Update CodeJar to 4.3.0, Node.js/ESLint, and D3-based visualization libs ([#5684](https://github.com/rspamd/rspamd/pull/5684), [#5717](https://github.com/rspamd/rspamd/pull/5717), [#5738](https://github.com/rspamd/rspamd/pull/5738))</li><li>**Bayes learn guards**: Make learn guards configurable instead of hardcoded ([#5701](https://github.com/rspamd/rspamd/pull/5701))</li><li>**Lua logger**: Add type specifiers support for better formatting ([#5668](https://github.com/rspamd/rspamd/pull/5668))</li><li>**DMARC reporting**: Refactor to use helper functions and async maps for better maintainability ([#5722](https://github.com/rspamd/rspamd/pull/5722))</li><li>**Config refcounting**: Add CFG_REF_* macros with debug logging for better lifecycle tracking ([#5709](https://github.com/rspamd/rspamd/pull/5709))</li><li>**Memory pool destructors**: Smart destructor preallocation based on pool type with specialized allocation strategies ([#5693](https://github.com/rspamd/rspamd/pull/5693))</li><li>**Heap implementation**: Convert to fully intrusive kvec-based implementation eliminating double allocation ([#5693](https://github.com/rspamd/rspamd/pull/5693))</li><li>**OpenSSL lifecycle**: Move providers from global to libs_ctx for clearer ownership ([#5709](https://github.com/rspamd/rspamd/pull/5709))</li><li>**Libucl stack management**: Automatic stack preservation for included files without outer braces ([#5717](https://github.com/rspamd/rspamd/pull/5717))</li><li>**Body rewriting**: Improve body rewriting support in rspamc and proxy ([#5675](https://github.com/rspamd/rspamd/pull/5675))</li><li>**AI assistant config**: Add Claude Code and Cursor AI configuration for development ([#5667](https://github.com/rspamd/rspamd/pull/5667))</li><li>**Fuzzy logging**: Add protocol logging and reduce dumb log verbosity ([#5669](https://github.com/rspamd/rspamd/pull/5669), [#5701](https://github.com/rspamd/rspamd/pull/5701))</li><li>**Docker configuration**: Add explicit console logging and runtime flags ([#5701](https://github.com/rspamd/rspamd/pull/5701))</li></ul>]]></description>
      <category>major</category>
    </item>
    <item>
      <title>Rspamd 3.13.2 - Feature Update with Enhanced Security and Performance</title>
      <link>https://docs.rspamd.com/changelog/3.13.2</link>
      <guid isPermaLink="false">https://docs.rspamd.com/changelog/3.13.2</guid>
      <pubDate>Sun, 05 Oct 2025 00:00:00 GMT</pubDate>
      <description><![CDATA[<h2>Rspamd 3.13.2 - Feature Update with Enhanced Security and Performance</h2><h3>Added</h3><ul><li>**Fuzzy check encryption**: Separate encryption keys for read and write operations in fuzzy_check plugin ([#5665](https://github.com/rspamd/rspamd/pull/5665))</li><li>**DKIM ED25519 support**: Full ED25519 support for DKIM signing and verification with OpenSSL version checks ([#5664](https://github.com/rspamd/rspamd/pull/5664))</li><li>**Vault KV v2 support**: HashiCorp Vault KV version 2 support for DKIM key management with backward compatibility ([#5654](https://github.com/rspamd/rspamd/pull/5654))</li><li>**MetaDefender integration**: MetaDefender Cloud Lua module for SHA256 hash lookups as free-tier anti-malware scanning alternative ([#5656](https://github.com/rspamd/rspamd/pull/5656))</li><li>**LLM context support**: User/domain context support for LLM-based classification with Redis-based conversation context ([#5647](https://github.com/rspamd/rspamd/pull/5647))</li><li>**DMARC RUA exclusion**: Configuration option to exclude specific RUA addresses from DMARC report storage ([#5653](https://github.com/rspamd/rspamd/pull/5653))</li></ul><h3>Fixed</h3><ul><li>**DKIM bodyhash calculation**: Fixed relaxed bodyhash calculation for lines with only spaces to comply with RFC 6376 Section 3.4.4 ([#5662](https://github.com/rspamd/rspamd/pull/5662))</li><li>**DKIM key loading**: Fixed ED25519 key loading to prevent memory corruption in union handling ([#5664](https://github.com/rspamd/rspamd/pull/5664))</li><li>**HTTP map intervals**: Enforced server-controlled refresh intervals and prevented aggressive polling behavior ([#5660](https://github.com/rspamd/rspamd/pull/5660))</li><li>**HTTP map overflow**: Prevented time_t overflow in expires header processing ([#5660](https://github.com/rspamd/rspamd/pull/5660))</li><li>**Once received plugin**: Fixed duplicate symbol addition by changing break to return in check_quantity_received ([#5658](https://github.com/rspamd/rspamd/pull/5658))</li><li>**Redis Sentinel**: Properly propagate unused Sentinel options ([#5597](https://github.com/rspamd/rspamd/pull/5597))</li><li>**Fuzzy check decryption**: Fixed reply decryption when using separate read/write keys ([#5665](https://github.com/rspamd/rspamd/pull/5665))</li><li>**Fuzzy check fallback**: Added fallback when only one specific encryption key is set ([#5665](https://github.com/rspamd/rspamd/pull/5665))</li><li>**Fuzzy check filtering**: Fixed duplicate key filtering in reply decryption ([#5665](https://github.com/rspamd/rspamd/pull/5665))</li><li>**Fuzzy ping servers**: Allow read/write servers configuration ([#5665](https://github.com/rspamd/rspamd/pull/5665))</li></ul><h3>Improved</h3><ul><li>**Fuzzy check performance**: Refactored encryption key selection into helper functions for better maintainability ([#5665](https://github.com/rspamd/rspamd/pull/5665))</li><li>**Fuzzy check efficiency**: Stop early when found a correct key to improve performance ([#5665](https://github.com/rspamd/rspamd/pull/5665))</li><li>**Development workflow**: Added cursor rules for improved development experience ([#5665](https://github.com/rspamd/rspamd/pull/5665))</li></ul>]]></description>
      <category>minor</category>
    </item>
    <item>
      <title>Rspamd 3.13.1 - Feature Update with Stability and Security Improvements</title>
      <link>https://docs.rspamd.com/changelog/3.13.1</link>
      <guid isPermaLink="false">https://docs.rspamd.com/changelog/3.13.1</guid>
      <pubDate>Tue, 30 Sep 2025 00:00:00 GMT</pubDate>
      <description><![CDATA[<h2>Rspamd 3.13.1 - Feature Update with Stability and Security Improvements</h2><h3>Added</h3><ul><li>**Archive module**: Full support for encrypted ZIP archives, including both ZipCrypto and AES encryption; both reading and writing of AES-encrypted ZIP archives is supported with updated Lua bindings using libarchive for flexible compatibility with all standard ZIP encryption schemes</li><li>**Encrypted maps**: Support for encrypted maps to enable new map distribution scenarios</li><li>**Redis TLS**: Configurable TLS connections in Redis backend for improved compatibility in secure environments</li></ul><h3>Improved</h3><ul><li>**MIME encoding refactoring**: Major overhauls and multiple fixes for MIME encoding logic, including improved handling and decoding of UTF-8 in MIME headers, resulting in more robust email processing and better compatibility</li><li>**Learning system**: Numerous fixes to learn checks and autolearn flag handling, prevention of duplicate message learning, and extended multiclass learning test coverage</li><li>**Map helpers alignment**: Map helpers now enforced to be aligned to 64 bytes to prevent unaligned memory access errors on certain platforms</li><li>**CLI enhancements**: Enhanced secretbox CLI and additional security test coverage</li><li>**Platform compatibility**: Improved compatibility with Lua versions above 5.1 and better support for 32-bit platforms</li></ul><h3>Fixed</h3><ul><li>**Critical fixes**: Fixed bug when converting zero-length strings to numbers</li><li>**XML parsing**: Fixed XML prolog detection in lua_magic module</li><li>**Build issues**: Fixed build issues on 32-bit platforms</li><li>**Empty input handling**: Addressed issues with empty input handling in lua_magic</li><li>**Test stability**: Improved stability of automated testing with multiple miscellaneous test fixes</li><li>**Compatibility**: Minor compatibility improvements and bugfixes (buffer allocation, missing cmath include, etc.)</li></ul>]]></description>
      <category>minor</category>
    </item>
    <item>
      <title>Rspamd 3.13.0 - Major Release with Breaking Changes</title>
      <link>https://docs.rspamd.com/changelog/3.13.0</link>
      <guid isPermaLink="false">https://docs.rspamd.com/changelog/3.13.0</guid>
      <pubDate>Wed, 17 Sep 2025 00:00:00 GMT</pubDate>
      <description><![CDATA[<h2>Rspamd 3.13.0 - Major Release with Breaking Changes</h2><h3>Breaking Changes</h3><ul><li>Multiclass Bayes classification with named classes (2–20 classes), processed in a single Redis call per message. ([#5547](https://github.com/rspamd/rspamd/pull/5547))</li><li>Backward compatible with `is_spam`; new configuration supports labeled classes and autolearn.</li><li>Lua API and autolearn support multiclass workflows with class‑aware Redis caching.</li><li>CLI: `rspamc learn_class:transactional …`, `rspamc learn_class:newsletter …`.</li><li>Lua API: `task:get_multiclass_result()` returns class probabilities and confidence.</li></ul><h3>Added</h3><ul><li>Neural module overhaul to a provider‑based architecture (symbols, LLM embeddings), versioned and backward compatible. ([#5579](https://github.com/rspamd/rspamd/pull/5579))</li><li>Pluggable feature fusion with trained normalization (unit/zscore/none) applied at train and inference.</li><li>Redis‑backed caching for LLM embeddings to control cost and latency.</li><li>Multimap selectors: SA‑style selectors with dedicated `selector` field; integrated with Hyperscan and regex cache. ([#5615](https://github.com/rspamd/rspamd/pull/5615))</li><li>MIME parser automatically detects part types. ([#5619](https://github.com/rspamd/rspamd/pull/5619), [#5608](https://github.com/rspamd/rspamd/pull/5608))</li><li>HTML parser extracts more features for downstream modules.</li></ul><h3>Improved</h3><ul><li>HTTP timeouts configuration and handling. ([#5614](https://github.com/rspamd/rspamd/pull/5614), [#5603](https://github.com/rspamd/rspamd/pull/5603), [#5601](https://github.com/rspamd/rspamd/pull/5601))</li><li>Upstream reliability with probe mode; reduced need for forced revive.</li><li>DNS nameserver resolution switched to `getaddrinfo`.</li><li>Standardized on C++20; build, test, and CI improvements (including ARM support and modern fallback maps). ([#5592](https://github.com/rspamd/rspamd/pull/5592), [#5598](https://github.com/rspamd/rspamd/pull/5598), [#5580](https://github.com/rspamd/rspamd/pull/5580))</li><li>Regular code cleaning and RPM tweaks.</li><li>WebUI: E2E scan test flows; Bootstrap upgrade; Bayes class management from the web interface. ([#5606](https://github.com/rspamd/rspamd/pull/5606), [#5607](https://github.com/rspamd/rspamd/pull/5607))</li><li>GPT/LLM integrations: improved parameter/prompt handling; initial support for OpenAI GPT‑5 and other models. ([#5612](https://github.com/rspamd/rspamd/pull/5612), [#5572](https://github.com/rspamd/rspamd/pull/5572))</li></ul><h3>Fixed</h3><ul><li>DCC plugin rewritten and optimized. ([#5602](https://github.com/rspamd/rspamd/pull/5602))</li><li>DKIM relaxed body canonicalization; improved reliability in multimap, WebUI, and configuration. ([#5593](https://github.com/rspamd/rspamd/pull/5593))</li><li>Numerous minor bug fixes and CI/build improvements.</li></ul>]]></description>
      <category>major</category>
    </item>
    <item>
      <title>Rspamd 3.12.1 - Minor Release with Bug Fixes and Improvements</title>
      <link>https://docs.rspamd.com/changelog/3.12.1</link>
      <guid isPermaLink="false">https://docs.rspamd.com/changelog/3.12.1</guid>
      <pubDate>Tue, 17 Jun 2025 00:00:00 GMT</pubDate>
      <description><![CDATA[<h2>Rspamd 3.12.1 - Minor Release with Bug Fixes and Improvements</h2><h3>Added</h3><ul><li>**Bayes Classifiers Endpoint**: Add `/bayes/classifiers` HTTP endpoint for better classifier management</li><li>**Enhanced Scheduling**: Further improvements in scheduling next checks for better performance</li><li>**AEAD Testing**: Add comprehensive tests for AEAD (Authenticated Encryption with Associated Data) used in Rspamd</li><li>**Improved Maps Consistency**: Better consistency in cached flag for maps and logging when dealing with Expires</li></ul><h3>Improved</h3><ul><li>**Maps Locking**: Eliminate maps locking for better performance and reduced contention</li><li>**Proxy Headers**: Fix proxy headers duplication and improve header handling</li><li>**Milter Logic**: Do not add log tag header in milter logic for cleaner output</li><li>**Connection Handling**: Do not explicitly add Connection header if it&apos;s already present</li><li>**Attachment Processing**: Treat *.library-ms and *.search-ms attachments as harmful (with proper application)</li><li>**Maps Concurrent Loading**: Fix race conditions in maps concurrent loading</li><li>**Write Operations**: Try to avoid incomplete writes for better data integrity</li></ul><h3>Fixed</h3><ul><li>**Maps Locking Issues**: Eliminate maps locking to prevent deadlocks and improve performance</li><li>**Proxy Headers Duplication**: Fix proxy headers duplication issue</li><li>**Milter Header Logic**: Fix logic error in milter_headers.lua: skip_wanted() function</li><li>**Connection Header**: Prevent duplicate Connection headers in proxy</li><li>**Maps Concurrent Access**: Fix race conditions in maps concurrent loading</li><li>**Incomplete Writes**: Prevent incomplete writes that could cause data corruption</li><li>**Attachment Security**: Properly apply security rules for *.library-ms and *.search-ms attachments</li><li>**Logging Consistency**: Improve consistency in logging when dealing with Expires and cached flags</li></ul><h3>Changed</h3><ul><li>**Maps Architecture**: Eliminate maps locking mechanism for better performance</li><li>**Header Processing**: Improve header processing to avoid duplicates</li><li>**Attachment Handling**: Enhanced security for Windows library and search attachments</li><li>**Scheduling Logic**: Improved scheduling algorithm for next checks</li><li>**Logging Format**: Better consistency in logging output and cached flag handling</li></ul><h3>Security</h3><ul><li>**Attachment Security**: Enhanced protection against potentially harmful Windows library and search attachments</li><li>**Header Validation**: Improved header validation to prevent duplication and injection</li><li>**Write Protection**: Better protection against incomplete writes that could lead to data corruption</li></ul><h3>Performance</h3><ul><li>**Maps Performance**: Eliminate maps locking for better concurrent access performance</li><li>**Scheduling**: Improved scheduling algorithm for better resource utilization</li><li>**Header Processing**: Optimized header processing to reduce overhead</li></ul><h3>Testing</h3><ul><li>**AEAD Testing**: Comprehensive tests for AEAD encryption used throughout Rspamd</li><li>**Maps Testing**: Improved testing for maps concurrent loading scenarios</li><li>**Header Testing**: Better testing for header processing and duplication scenarios</li></ul>]]></description>
      <category>minor</category>
    </item>
    <item>
      <title>Rspamd 3.12.0 - Major Release with Enhanced Features and Security Improvements</title>
      <link>https://docs.rspamd.com/changelog/3.12.0</link>
      <guid isPermaLink="false">https://docs.rspamd.com/changelog/3.12.0</guid>
      <pubDate>Tue, 10 Jun 2025 00:00:00 GMT</pubDate>
      <description><![CDATA[<h2>Rspamd 3.12.0 - Major Release with Enhanced Features and Security Improvements</h2><h3>Added</h3><ul><li>**GPT Module Enhancements**: Add Ollama support and token usage logging for OpenAI-compatible APIs</li><li>**Fuzzy Storage Improvements**: Add support for separate read and write servers in fuzzy check</li><li>**CDB Maps Support**: Allow CDB files as external maps for improved performance</li><li>**Contextal Integration**: New plugin to integrate with Contextal platform for advanced threat detection</li><li>**Enhanced Logging**: Allow to specify max log tag length for all log messages and log tag in proxy</li><li>**Proxy Improvements**: Add keep-alive support, HTTPS backend connections, and extra headers specification</li><li>**Redis Version Support**: Allow to specify Redis version for compatibility</li><li>**HEIC File Support**: Add HEIC files patterns for better image analysis</li><li>**Enhanced Maps Management**: Show all maps status and output content for all maps</li><li>**File Upload in WebUI**: Add file upload functionality to Test Selectors</li><li>**Convenience Methods**: Add various convenience methods for Lua development</li><li>**Enhanced Fuzzy Operations**: Add deletion of specific fuzzy hashes in WebUI</li><li>**Improved Error Handling**: Better error messages for multimap invalid types</li></ul><h3>Improved</h3><ul><li>**Security Enhancements**: Critical fix to disable macros and file variables by default in lua-ucl</li><li>**Maps Loading**: Fix race condition in maps loading by unlocking backend on switch</li><li>**Greylisting**: Improve body hash calculations for better accuracy</li><li>**Replies Module**: Rework to consider all recipients and use SMTP ones</li><li>**WebUI Updates**: Update Bootstrap, D3 and PrismJS libraries to latest versions</li><li>**Lua Logging**: Major improvements to logging output format and complex table key support</li><li>**Fuzzy Storage**: Better handling of fuzzy lua callback when there are no shingles</li><li>**Milter Headers**: Fix logic error in skip_wanted() function</li><li>**Known Senders**: Improved recipients test logic and consistency with replies module</li><li>**Maps Management**: Grey out not loaded maps in the Maps table for better visibility</li><li>**Redis Integration**: Improve Redis script loading and caching framework usage</li><li>**Configuration**: Use safe parsers everywhere except configuration for security</li><li>**Build System**: Modernize cmake and improve sanitizers support</li><li>**Documentation**: Update API docs for multiple HTTP headers and various other improvements</li></ul><h3>Fixed</h3><ul><li>**Critical Security**: Disable macros and file variables by default in lua-ucl parser</li><li>**Race Conditions**: Fix race condition in maps loading by unlocking backend on switch</li><li>**Memory Issues**: Fix lua-bit stack buffer overflow vulnerability</li><li>**Proxy Crashes**: Prevent crashes when accessing upstream address in self-scan mode</li><li>**Maps Management**: Fix maps IDs and static maps description passing</li><li>**Fuzzy Storage**: Filter invalid domains in fuzzy extra data</li><li>**Redis Integration**: Fix various Redis-related issues and improve script loading</li><li>**WebUI Issues**: Fix Fuzzy hashes card close button alignment and map editor modal handling</li><li>**Build Issues**: Fix Debian package build and RPM log directory attributes</li><li>**Compiler Warnings**: Fix various compile warnings and compatibility issues</li><li>**Test Framework**: Fix various test issues and improve test configuration</li><li>**Documentation**: Fix writing rules tutorial link and various documentation issues</li><li>**URL Lists**: Update default URL for openphish and fix various URL-related issues</li><li>**Headers Processing**: Fix header processing in various modules</li><li>**Lua Integration**: Fix various Lua-related issues and improve error handling</li></ul><h3>Changed</h3><ul><li>**Configuration**: Use safe parsers everywhere except configuration for enhanced security</li><li>**Maps Architecture**: Rework to use locks/loaded per backend for all maps</li><li>**Replies Logic**: Consider all recipients and use SMTP ones instead of just From header</li><li>**Fuzzy Storage**: Remove servers completely and use `read_servers` for all compatibility</li><li>**Logging Format**: Improve format string processing and logging output</li><li>**Build System**: Modernize cmake and rework OSDep for better maintainability</li><li>**WebUI**: Rework file upload JS implementation and improve user interface</li><li>**Documentation**: Update various documentation files and improve API documentation</li><li>**Error Handling**: Improve error messages and handling throughout the codebase</li><li>**Performance**: Various performance improvements in maps, Redis, and fuzzy operations</li></ul><h3>Removed</h3><ul><li>**Deprecated Features**: Remove various deprecated and unused code paths</li><li>**Unused Helpers**: Remove unused cleanTextUpload helper and other obsolete code</li><li>**Legacy Support**: Remove compatibility code that is no longer needed</li></ul><h3>Security</h3><ul><li>**Critical Fix**: Disable macros and file variables by default in lua-ucl parser</li><li>**Memory Safety**: Fix lua-bit stack buffer overflow vulnerability</li><li>**Input Validation**: Improve input validation and error handling throughout</li><li>**Configuration Security**: Use safe parsers everywhere except configuration</li></ul><h3>Performance</h3><ul><li>**Maps Loading**: Optimize maps loading with better caching and race condition fixes</li><li>**Redis Operations**: Improve Redis script loading and caching framework usage</li><li>**Fuzzy Storage**: Better handling of fuzzy operations and storage management</li><li>**Memory Usage**: Various memory optimization improvements</li></ul><h3>Documentation</h3><ul><li>**API Documentation**: Update API docs for multiple HTTP headers and various modules</li><li>**Tutorial Links**: Fix writing rules tutorial link and other documentation references</li><li>**Examples**: Add more examples for Lua HTTP and other modules</li><li>**Configuration**: Improve configuration documentation and examples</li></ul><h3>Testing</h3><ul><li>**Test Framework**: Fix various test issues and improve test configuration</li><li>**Fuzzy Tests**: Add comprehensive tests for split, read-only, and write-only server modes</li><li>**CDB Maps**: Add tests for CDB maps functionality</li><li>**HEIC Recognition**: Add tests for HEIC file recognition</li></ul>]]></description>
      <category>major</category>
    </item>
    <item>
      <title>Rspamd 3.11.1 - Feature Update with Bug Fixes</title>
      <link>https://docs.rspamd.com/changelog/3.11.1</link>
      <guid isPermaLink="false">https://docs.rspamd.com/changelog/3.11.1</guid>
      <pubDate>Sun, 15 Dec 2024 00:00:00 GMT</pubDate>
      <description><![CDATA[<h2>Rspamd 3.11.1 - Feature Update with Bug Fixes</h2><h3>Added</h3><ul><li>GPT: Add ollama support</li><li>Allow to hash any Lua types</li><li>Allow to use LLM for anonymize</li><li>Add ability to not send response_format in gpt plugin to support gpt4all</li><li>Allow to store shingles as opaque Lua data</li><li>Add &apos;noop&apos; redis backend for scripts running</li><li>Allow multiple lua scripts for fuzzy storage</li><li>Support LLM models consensus</li><li>GPT: Support reason adding</li><li>Add Redis caching framework</li><li>Add ability to create timers from Lua</li></ul><h3>Improved</h3><ul><li>Expand Detection of Fake Reply Subjects Across Multiple Languages</li><li>Add another acceptable mime type for icon</li><li>Respect ipv4 and ipv6 configurations for rbl resolve_ip</li><li>Set RBL checks to bool true</li><li>Rules regexp url separated and fix no subdomain cases for Google urls</li><li>WebUI: Reset dropdown when clearing filters</li><li>Pass both the multimap and the rules descriptions for combined multimap on create</li><li>Some small fixes to statistics_dump</li><li>More features to GPT plugin</li><li>Better support for maps and IP-related fixes/improvements in settings</li><li>Use caching framework in gpt module</li><li>Try to check maps earlier if their expires is too long</li></ul><h3>Fixed</h3><ul><li>Fix transposed results in `rspamadm fuzzy_ping`</li><li>connIp is not correctly added to request</li><li>Fix Thunderbird for Android marked with FORGED_MUA_THUNDERBIRD_MSGID_UNKNOWN</li><li>Fix issue with synchronous Redis calls</li><li>Fix some broken links</li><li>rbl check_types was missing images</li><li>RBL: fix use of `content_urls` and `images` inside `checks`</li><li>Use sub_utf8 to strip headers value to not break utf8 strings</li><li>Properly close multipart/related boundary when adding text footer</li><li>Verify key type to match DKIM signature type</li><li>Avoid collision hacks in mempool variables hash</li><li>Add expiration for neural ham and spam sets</li><li>Properly expire neural ham and spam sets</li></ul><h3>Changed</h3><ul><li>Log queue id with cloudmark analysis string</li><li>Allow to disable RBLs via map</li><li>Prevent option duplicates in rspamd_stats.pl</li><li>Regenerate manpages with recent Pandoc version</li><li>Fix spelling errors in libserver</li><li>Update JavaScript linters</li></ul><h3>Removed</h3><ul><li>Remove nixspam</li></ul>]]></description>
      <category>minor</category>
    </item>
    <item>
      <title>Rspamd 3.11.0 - Major Release with Breaking Changes</title>
      <link>https://docs.rspamd.com/changelog/3.11.0</link>
      <guid isPermaLink="false">https://docs.rspamd.com/changelog/3.11.0</guid>
      <pubDate>Sun, 01 Dec 2024 00:00:00 GMT</pubDate>
      <description><![CDATA[<h2>Rspamd 3.11.0 - Major Release with Breaking Changes</h2><h3>Breaking Changes</h3><ul><li>**Elasticsearch/OpenSearch Plugin**: Major rework with breaking changes</li><li>Added support for Elasticsearch 8 &amp; OpenSearch 2</li><li>Added index policy with logs retention</li><li>Updated configuration format</li></ul><h3>Added</h3><ul><li>Added LRU cache for last filled ratelimit buckets</li><li>Added utilities to manage ratelimit buckets</li><li>Added include/exclude logic for headers processing</li><li>Added `rspamadm mime strip` command for attachments removal</li><li>Added new message anonymization capabilities</li><li>Added more ways to extend Rspamd configuration, including `lua.local.d` folder</li></ul><h3>Improved</h3><ul><li>Improved address rotation algorithm for upstream selection</li><li>Replaced fastutf with simdutf for better architecture support and performance</li><li>Reworked symbol description display on hover in WebUI</li><li>Improved keyboard accessibility in WebUI</li><li>Enhanced symbol rendering in WebUI</li><li>Improved handling of DNS limits in SPF module</li><li>Improved GPT module JSON parsing</li><li>Multiple performance optimizations</li></ul><h3>Fixed</h3><ul><li>Fixed ARC-Seal signing issues</li><li>Fixed RFC 2047 header encoding</li><li>Fixed issues with dynamic keys in fuzzy storage</li><li>Fixed TCP connection handling with cumulative timeouts</li><li>Fixed multiple phishing detection false positives</li><li>Fixed DMARC structured headers encoding</li></ul><h3>Changed</h3><ul><li>Skip extra RBL checks when Received IP matches From IP</li><li>Multimap now uses only distinct text parts for content matching</li><li>Various configuration and logging improvements</li></ul>]]></description>
      <category>major</category>
    </item>
  </channel>
</rss>