Version in base suite: 2.3.19.1+dfsg1-2.1+deb12u1 Base version: dovecot_2.3.19.1+dfsg1-2.1+deb12u1 Target version: dovecot_2.3.19.1+dfsg1-2.1+deb12u2 Base file: /srv/ftp-master.debian.org/ftp/pool/main/d/dovecot/dovecot_2.3.19.1+dfsg1-2.1+deb12u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/d/dovecot/dovecot_2.3.19.1+dfsg1-2.1+deb12u2.dsc changelog | 20 ++ dovecot-core.examples | 1 patches/CVE-2025-59031.patch | 133 +++++++++++++++++++ patches/CVE-2025-59032.patch | 33 ++++ patches/CVE-2026-0394-1.patch | 66 +++++++++ patches/CVE-2026-0394-2.patch | 59 ++++++++ patches/CVE-2026-27855-1.patch | 23 +++ patches/CVE-2026-27855-2.patch | 91 +++++++++++++ patches/CVE-2026-27855-3.patch | 41 ++++++ patches/CVE-2026-27855-4.patch | 27 +++ patches/CVE-2026-27856-1.patch | 51 +++++++ patches/CVE-2026-27856-2.patch | 51 +++++++ patches/CVE-2026-27856-3.patch | 23 +++ patches/CVE-2026-27857-1.patch | 24 +++ patches/CVE-2026-27857-2.patch | 280 +++++++++++++++++++++++++++++++++++++++++ patches/CVE-2026-27857-3.patch | 160 +++++++++++++++++++++++ patches/CVE-2026-27857-4.patch | 84 ++++++++++++ patches/CVE-2026-27857-5.patch | 59 ++++++++ patches/CVE-2026-27858.patch | 28 ++++ patches/CVE-2026-27859.patch | 103 +++++++++++++++ patches/series | 18 ++ rules | 1 22 files changed, 1374 insertions(+), 2 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpne6weu6y/dovecot_2.3.19.1+dfsg1-2.1+deb12u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpne6weu6y/dovecot_2.3.19.1+dfsg1-2.1+deb12u2.dsc: no acceptable signature found diff -Nru dovecot-2.3.19.1+dfsg1/debian/changelog dovecot-2.3.19.1+dfsg1/debian/changelog --- dovecot-2.3.19.1+dfsg1/debian/changelog 2024-08-18 14:25:33.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/changelog 2026-04-03 17:58:21.000000000 +0000 @@ -1,3 +1,23 @@ +dovecot (1:2.3.19.1+dfsg1-2.1+deb12u2) bookworm-security; urgency=medium + + * [34fb460] import upstream fixes for several CVEs + - CVE-2025-59031: Remove unsafe decode2text shell script + - CVE-2025-59032: ManageSieve AUTHENTICATE command crashes when using + literal as SASL initial response + - CVE-2026-0394: potential path traversal when configured to use + per-domain passwd + - CVE-2026-27855: OTP driver vulnerable to replay attack. + - CVE-2026-27856: Doveadm credentials were not checked using + timing-safe checking function + - CVE-2026-27857: Sending excessive parenthesis causes imap-login to + use excessive memory + - CVE-2026-27858: managesieve-login can allocate large amount of + memory during authentication + - CVE-2026-27859: Excessive RFC 2231 MIME parameters in email would + cause excessive CPU usage + + -- Noah Meyerhans Fri, 03 Apr 2026 13:58:21 -0400 + dovecot (1:2.3.19.1+dfsg1-2.1+deb12u1) bookworm-security; urgency=medium * Security team upload: diff -Nru dovecot-2.3.19.1+dfsg1/debian/dovecot-core.examples dovecot-2.3.19.1+dfsg1/debian/dovecot-core.examples --- dovecot-2.3.19.1+dfsg1/debian/dovecot-core.examples 2023-06-27 04:04:57.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/dovecot-core.examples 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -src/plugins/fts/decode2text.sh diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2025-59031.patch dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2025-59031.patch --- dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2025-59031.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2025-59031.patch 2026-04-03 17:58:21.000000000 +0000 @@ -0,0 +1,133 @@ +From 089edc7750160bf224011c015347db1bdea435e3 Mon Sep 17 00:00:00 2001 +From: Aki Tuomi +Date: Thu, 8 Jan 2026 08:51:59 +0200 +Subject: [PATCH 02/24] fts: Remove decode2text.sh + +The script is flawed and not fit for production use, should +recommend writing your own script, or using Apache Tika. +--- + src/plugins/fts/Makefile.am | 3 - + src/plugins/fts/decode2text.sh | 105 --------------------------------- + 2 files changed, 108 deletions(-) + delete mode 100755 src/plugins/fts/decode2text.sh + +--- dovecot-2.3.21+dfsg1.orig/src/plugins/fts/Makefile.am ++++ dovecot-2.3.21+dfsg1/src/plugins/fts/Makefile.am +@@ -63,9 +63,6 @@ xml2text_CPPFLAGS = $(AM_CPPFLAGS) $(BIN + xml2text_LDADD = $(LIBDOVECOT) $(BINARY_LDFLAGS) + xml2text_DEPENDENCIES = $(module_LTLIBRARIES) $(LIBDOVECOT_DEPS) + +-pkglibexec_SCRIPTS = decode2text.sh +-EXTRA_DIST = $(pkglibexec_SCRIPTS) +- + doveadm_module_LTLIBRARIES = \ + lib20_doveadm_fts_plugin.la + +--- dovecot-2.3.21+dfsg1.orig/src/plugins/fts/decode2text.sh ++++ /dev/null +@@ -1,105 +0,0 @@ +-#!/bin/sh +- +-# Example attachment decoder script. The attachment comes from stdin, and +-# the script is expected to output UTF-8 data to stdout. (If the output isn't +-# UTF-8, everything except valid UTF-8 sequences are dropped from it.) +- +-# The attachment decoding is enabled by setting: +-# +-# plugin { +-# fts_decoder = decode2text +-# } +-# service decode2text { +-# executable = script /usr/local/libexec/dovecot/decode2text.sh +-# user = dovecot +-# unix_listener decode2text { +-# mode = 0666 +-# } +-# } +- +-libexec_dir=`dirname $0` +-content_type=$1 +- +-# The second parameter is the format's filename extension, which is used when +-# found from a filename of application/octet-stream. You can also add more +-# extensions by giving more parameters. +-formats='application/pdf pdf +-application/x-pdf pdf +-application/msword doc +-application/mspowerpoint ppt +-application/vnd.ms-powerpoint ppt +-application/ms-excel xls +-application/x-msexcel xls +-application/vnd.ms-excel xls +-application/vnd.openxmlformats-officedocument.wordprocessingml.document docx +-application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx +-application/vnd.openxmlformats-officedocument.presentationml.presentation pptx +-application/vnd.oasis.opendocument.text odt +-application/vnd.oasis.opendocument.spreadsheet ods +-application/vnd.oasis.opendocument.presentation odp +-' +- +-if [ "$content_type" = "" ]; then +- echo "$formats" +- exit 0 +-fi +- +-fmt=`echo "$formats" | grep -w "^$content_type" | cut -d ' ' -f 2` +-if [ "$fmt" = "" ]; then +- echo "Content-Type: $content_type not supported" >&2 +- exit 1 +-fi +- +-# most decoders can't handle stdin directly, so write the attachment +-# to a temp file +-path=`mktemp` +-trap "rm -f $path" 0 1 2 3 14 15 +-cat > $path +- +-xmlunzip() { +- name=$1 +- +- tempdir=`mktemp -d` +- if [ "$tempdir" = "" ]; then +- exit 1 +- fi +- trap "rm -rf $path $tempdir" 0 1 2 3 14 15 +- cd $tempdir || exit 1 +- unzip -q "$path" 2>/dev/null || exit 0 +- find . -name "$name" -print0 | xargs -0 cat | +- $libexec_dir/xml2text +-} +- +-wait_timeout() { +- childpid=$! +- trap "kill -9 $childpid; rm -f $path" 1 2 3 14 15 +- wait $childpid +-} +- +-LANG=en_US.UTF-8 +-export LANG +-if [ $fmt = "pdf" ]; then +- /usr/bin/pdftotext $path - 2>/dev/null& +- wait_timeout 2>/dev/null +-elif [ $fmt = "doc" ]; then +- (/usr/bin/catdoc $path; true) 2>/dev/null& +- wait_timeout 2>/dev/null +-elif [ $fmt = "ppt" ]; then +- (/usr/bin/catppt $path; true) 2>/dev/null& +- wait_timeout 2>/dev/null +-elif [ $fmt = "xls" ]; then +- (/usr/bin/xls2csv $path; true) 2>/dev/null& +- wait_timeout 2>/dev/null +-elif [ $fmt = "odt" -o $fmt = "ods" -o $fmt = "odp" ]; then +- xmlunzip "content.xml" +-elif [ $fmt = "docx" ]; then +- xmlunzip "document.xml" +-elif [ $fmt = "xlsx" ]; then +- xmlunzip "sharedStrings.xml" +-elif [ $fmt = "pptx" ]; then +- xmlunzip "slide*.xml" +-else +- echo "Buggy decoder script: $fmt not handled" >&2 +- exit 1 +-fi +-exit 0 diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2025-59032.patch dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2025-59032.patch --- dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2025-59032.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2025-59032.patch 2026-04-03 17:58:21.000000000 +0000 @@ -0,0 +1,33 @@ +From efb68fac3a9d2d04d38c4ab14dd570cf0c23923c Mon Sep 17 00:00:00 2001 +From: Timo Sirainen +Date: Mon, 22 Dec 2025 22:25:04 +0200 +Subject: [PATCH] managesieve-login: Fix crash when command didn't finish on + the first call + +--- + src/managesieve-login/client.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +Index: dovecot/pigeonhole/src/managesieve-login/client.c +=================================================================== +--- dovecot.orig/pigeonhole/src/managesieve-login/client.c ++++ dovecot/pigeonhole/src/managesieve-login/client.c +@@ -330,10 +330,14 @@ static bool managesieve_client_input_nex + if (args[0].type != MANAGESIEVE_ARG_EOL) + ret = -1; + } +- } +- if (ret > 0) { +- i_assert(client->cmd != NULL); +- ret = client->cmd->func(client, args); ++ if (ret > 0) { ++ i_assert(client->cmd != NULL); ++ ret = client->cmd->func(client, args); ++ } else { ++ /* Continue unfinished command */ ++ i_assert(client->cmd != NULL); ++ ret = client->cmd->func(client, NULL); ++ } + } + + if (ret != 0) diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-0394-1.patch dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-0394-1.patch --- dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-0394-1.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-0394-1.patch 2026-04-03 17:58:21.000000000 +0000 @@ -0,0 +1,66 @@ +From c4fbf9a46ebabb7a580087033ee1b841e52d905e Mon Sep 17 00:00:00 2001 +From: Aki Tuomi +Date: Wed, 13 Nov 2024 11:38:30 +0200 +Subject: [PATCH] auth: db-passwd-file - Add db_passwd_fix_path() + +--- + src/auth/db-passwd-file.c | 25 +++++++++++++++++++++++++ + src/auth/db-passwd-file.h | 2 ++ + 2 files changed, 27 insertions(+) + +Index: dovecot/src/auth/db-passwd-file.c +=================================================================== +--- dovecot.orig/src/auth/db-passwd-file.c ++++ dovecot/src/auth/db-passwd-file.c +@@ -14,6 +14,7 @@ + #include "str.h" + #include "eacces-error.h" + #include "ioloop.h" ++#include "path-util.h" + + #include + #include +@@ -420,6 +421,30 @@ void db_passwd_file_unref(struct db_pass + i_free(db); + } + ++int db_passwd_fix_path(const char *path, const char **path_r, ++ const char *orig_path, const char **error_r) ++{ ++ /* normalize path */ ++ const char *normalized; ++ if (t_normpath(path, &normalized, error_r) < 0) ++ return -1; ++ ++ /* check base path */ ++ const char *p; ++ if (*orig_path != '%' && ++ (p = strstr(orig_path, "%{")) != NULL) { ++ ptrdiff_t len = p - orig_path; ++ if (strncmp(orig_path, normalized, len) != 0) { ++ *error_r = t_strdup_printf("Path is outside '%s'", ++ t_strdup_until(orig_path, p)); ++ return -1; ++ } ++ } ++ ++ *path_r = normalized; ++ return 0; ++} ++ + static const char * + path_fix(const char *path, + const struct auth_request *auth_request ATTR_UNUSED) +Index: dovecot/src/auth/db-passwd-file.h +=================================================================== +--- dovecot.orig/src/auth/db-passwd-file.h ++++ dovecot/src/auth/db-passwd-file.h +@@ -45,6 +45,8 @@ struct db_passwd_file { + bool userdb_warn_missing:1; + }; + ++int db_passwd_fix_path(const char *path, const char **path_r, ++ const char *orig_path, const char **error_r); + int db_passwd_file_lookup(struct db_passwd_file *db, + struct auth_request *request, + const char *username_format, diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-0394-2.patch dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-0394-2.patch --- dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-0394-2.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-0394-2.patch 2026-04-03 17:58:21.000000000 +0000 @@ -0,0 +1,59 @@ +From 7fb773cffa3d78b587c406ebfeaa5a1e911a1835 Mon Sep 17 00:00:00 2001 +From: Aki Tuomi +Date: Wed, 13 Nov 2024 11:42:05 +0200 +Subject: [PATCH] auth: db-passwd-file - Normalize path with + db_passwd_fix_path() + +Otherwise there is a chance that we leak one ../ +--- + src/auth/db-passwd-file.c | 22 ++++++---------------- + 1 file changed, 6 insertions(+), 16 deletions(-) + +Index: dovecot/src/auth/db-passwd-file.c +=================================================================== +--- dovecot.orig/src/auth/db-passwd-file.c ++++ dovecot/src/auth/db-passwd-file.c +@@ -445,21 +445,6 @@ int db_passwd_fix_path(const char *path, + return 0; + } + +-static const char * +-path_fix(const char *path, +- const struct auth_request *auth_request ATTR_UNUSED) +-{ +- const char *p; +- +- p = strchr(path, '/'); +- if (p == NULL) +- return path; +- +- /* most likely this is an invalid request. just cut off the '/' and +- everything after it. */ +- return t_strdup_until(path, p); +-} +- + int db_passwd_file_lookup(struct db_passwd_file *db, + struct auth_request *request, + const char *username_format, +@@ -474,14 +459,19 @@ int db_passwd_file_lookup(struct db_pass + pw = db->default_file; + else { + dest = t_str_new(256); +- if (auth_request_var_expand(dest, db->path, request, path_fix, ++ if (auth_request_var_expand(dest, db->path, request, NULL, + &error) <= 0) { + e_error(authdb_event(request), + "Failed to expand passwd-file path %s: %s", + db->path, error); + return -1; + } +- ++ const char *path; ++ if (db_passwd_fix_path(str_c(dest), &path, db->path, &error) < 0) { ++ e_info(authdb_event(request), "Failed to normalize path: %s", ++ error); ++ return 0; ++ } + pw = hash_table_lookup(db->files, str_c(dest)); + if (pw == NULL) { + /* doesn't exist yet. create lookup for it. */ diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27855-1.patch dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27855-1.patch --- dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27855-1.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27855-1.patch 2026-04-03 17:58:21.000000000 +0000 @@ -0,0 +1,23 @@ +From f1bc3ea8ba747fcfe14ab56685d400e4e3cff130 Mon Sep 17 00:00:00 2001 +From: Aki Tuomi +Date: Mon, 9 Mar 2026 20:04:27 +0200 +Subject: [PATCH 21/24] auth: cache - Use translated username in + auth_cache_remove() + +--- + src/auth/auth-cache.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: dovecot/src/auth/auth-cache.c +=================================================================== +--- dovecot.orig/src/auth/auth-cache.c ++++ dovecot/src/auth/auth-cache.c +@@ -472,7 +472,7 @@ void auth_cache_remove(struct auth_cache + { + struct auth_cache_node *node; + +- key = auth_request_expand_cache_key(request, key, request->fields.user); ++ key = auth_request_expand_cache_key(request, key, request->fields.translated_username); + node = hash_table_lookup(cache->hash, key); + if (node == NULL) + return; diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27855-2.patch dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27855-2.patch --- dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27855-2.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27855-2.patch 2026-04-03 17:58:21.000000000 +0000 @@ -0,0 +1,91 @@ +From f2119a25a439f599b0a30fc674300b8f354e5b67 Mon Sep 17 00:00:00 2001 +From: Aki Tuomi +Date: Wed, 11 Mar 2026 12:30:32 +0200 +Subject: [PATCH 22/24] auth: Move passdb event lifecycle handling to + auth_request_passdb_event_(begin|end) + +--- + +From f2119a25a439f599b0a30fc674300b8f354e5b67 Mon Sep 17 00:00:00 2001 +From: Aki Tuomi +Date: Wed, 11 Mar 2026 12:30:32 +0200 +Subject: [PATCH 22/24] auth: Move passdb event lifecycle handling to + auth_request_passdb_event_(begin|end) + +--- + src/auth/auth-request.c | 39 +++++++++++++++++++++++++++------------ + src/auth/auth-request.h | 3 +++ + 2 files changed, 30 insertions(+), 12 deletions(-) + +Index: dovecot/src/auth/auth-request.c +=================================================================== +--- dovecot.orig/src/auth/auth-request.c ++++ dovecot/src/auth/auth-request.c +@@ -621,7 +621,7 @@ auth_request_cache_result_to_str(enum au + } + } + +-void auth_request_passdb_lookup_begin(struct auth_request *request) ++void auth_request_passdb_event_begin(struct auth_request *request) + { + struct event *event; + const char *name; +@@ -648,11 +648,33 @@ void auth_request_passdb_lookup_begin(st + else if (*request->passdb->set->auth_verbose == 'n') + event_set_min_log_level(event, LOG_TYPE_WARNING); + ++ array_push_back(&request->authdb_event, &event); ++} ++ ++void auth_request_passdb_event_end(struct auth_request *request) ++{ ++ struct event *event = authdb_event(request); ++ event_unref(&event); ++ array_pop_back(&request->authdb_event); ++ ++ /* restore protocol-specific settings */ ++ request->set = global_auth_settings; ++} ++ ++void auth_request_passdb_lookup_begin(struct auth_request *request) ++{ ++ struct event *event; ++ ++ i_assert(request->passdb != NULL); ++ i_assert(!request->userdb_lookup); ++ auth_request_passdb_event_begin(request); ++ ++ event = authdb_event(request); ++ + e_debug(event_create_passthrough(event)-> + set_name("auth_passdb_request_started")-> + event(), + "Performing passdb lookup"); +- array_push_back(&request->authdb_event, &event); + } + + void auth_request_passdb_lookup_end(struct auth_request *request, +@@ -668,8 +690,7 @@ void auth_request_passdb_lookup_end(stru + request->set->cache_ttl != 0 && request->set->cache_size != 0) + e->add_str("cache", auth_request_cache_result_to_str(request->passdb_cache_result)); + e_debug(e->event(), "Finished passdb lookup"); +- event_unref(&event); +- array_pop_back(&request->authdb_event); ++ auth_request_passdb_event_end(request); + } + + void auth_request_userdb_lookup_begin(struct auth_request *request) +Index: dovecot/src/auth/auth-request.h +=================================================================== +--- dovecot.orig/src/auth/auth-request.h ++++ dovecot/src/auth/auth-request.h +@@ -373,6 +373,9 @@ void auth_request_master_user_login_fini + const char *auth_request_get_log_prefix_db(struct auth_request *auth_request); + void auth_request_fields_init(struct auth_request *request); + ++void auth_request_passdb_event_begin(struct auth_request *request); ++void auth_request_passdb_event_end(struct auth_request *request); ++ + void auth_request_passdb_lookup_begin(struct auth_request *request); + void auth_request_passdb_lookup_end(struct auth_request *request, + enum passdb_result result); diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27855-3.patch dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27855-3.patch --- dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27855-3.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27855-3.patch 2026-04-03 17:58:21.000000000 +0000 @@ -0,0 +1,41 @@ +From 8fd279db61be2054c8f3e7275766717318a2df91 Mon Sep 17 00:00:00 2001 +From: Aki Tuomi +Date: Mon, 9 Mar 2026 21:23:29 +0200 +Subject: [PATCH 23/24] auth: Initialize set_credentials event properly + +Fixes update_query +--- + +From 8fd279db61be2054c8f3e7275766717318a2df91 Mon Sep 17 00:00:00 2001 +From: Aki Tuomi +Date: Mon, 9 Mar 2026 21:23:29 +0200 +Subject: [PATCH 23/24] auth: Initialize set_credentials event properly + +Fixes update_query +--- + src/auth/auth-request.c | 4 ++++ + src/auth/auth-worker-server.c | 2 ++ + 2 files changed, 6 insertions(+) + +Index: dovecot/src/auth/auth-request.c +=================================================================== +--- dovecot.orig/src/auth/auth-request.c ++++ dovecot/src/auth/auth-request.c +@@ -1341,6 +1341,8 @@ void auth_request_set_credentials(struct + struct auth_passdb *passdb = request->passdb; + const char *cache_key, *new_credentials; + ++ auth_request_passdb_event_begin(request); ++ + cache_key = passdb_cache == NULL ? NULL : passdb->cache_key; + if (cache_key != NULL) + auth_cache_remove(passdb_cache, request, cache_key); +@@ -1357,6 +1359,8 @@ void auth_request_set_credentials(struct + /* this passdb doesn't support credentials update */ + callback(FALSE, request); + } ++ ++ auth_request_passdb_event_end(request); + } + + static void auth_request_userdb_save_cache(struct auth_request *request, diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27855-4.patch dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27855-4.patch --- dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27855-4.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27855-4.patch 2026-04-03 17:58:21.000000000 +0000 @@ -0,0 +1,27 @@ +From 535a14209810e7b0c8f94479daf580ac4c637904 Mon Sep 17 00:00:00 2001 +From: Aki Tuomi +Date: Wed, 11 Mar 2026 12:46:53 +0200 +Subject: [PATCH 24/24] auth: passdb-sql - Require update_query to be set when + used + +--- + src/auth/passdb-sql.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +Index: dovecot/src/auth/passdb-sql.c +=================================================================== +--- dovecot.orig/src/auth/passdb-sql.c ++++ dovecot/src/auth/passdb-sql.c +@@ -247,6 +247,12 @@ static void sql_set_credentials(struct a + return; + } + ++ if (*query == '\0') { ++ e_error(authdb_event(request), "update_query is empty"); ++ callback(FALSE, request); ++ return; ++ } ++ + sql_request = i_new(struct passdb_sql_request, 1); + sql_request->auth_request = request; + sql_request->callback.set_credentials = callback; diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27856-1.patch dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27856-1.patch --- dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27856-1.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27856-1.patch 2026-04-03 17:58:21.000000000 +0000 @@ -0,0 +1,51 @@ +From 6ef282fab8af8faec75b0ff8cb87b11094642ba0 Mon Sep 17 00:00:00 2001 +From: Aki Tuomi +Date: Wed, 4 Mar 2026 08:05:13 +0200 +Subject: [PATCH 16/24] doveadm: client-connection - Use timing safe credential + check + +--- + src/doveadm/client-connection-http.c | 7 +++++-- + src/doveadm/client-connection-tcp.c | 4 +--- + 2 files changed, 6 insertions(+), 5 deletions(-) + +Index: dovecot/src/doveadm/client-connection-http.c +=================================================================== +--- dovecot.orig/src/doveadm/client-connection-http.c ++++ dovecot/src/doveadm/client-connection-http.c +@@ -984,7 +984,9 @@ doveadm_http_server_auth_basic(struct cl + value = p_strdup_printf(conn->conn.pool, + "doveadm:%s", set->doveadm_password); + base64_encode(value, strlen(value), b64_value); +- if (creds->data != NULL && strcmp(creds->data, str_c(b64_value)) == 0) ++ ++ if (creds->data != NULL && ++ str_equals_timing_almost_safe(value, creds->data)) + return TRUE; + + i_error("Invalid authentication attempt to HTTP API " +@@ -1009,7 +1011,8 @@ doveadm_http_server_auth_api_key(struct + b64_value = str_new(conn->conn.pool, 32); + base64_encode(set->doveadm_api_key, + strlen(set->doveadm_api_key), b64_value); +- if (creds->data != NULL && strcmp(creds->data, str_c(b64_value)) == 0) ++ if (creds->data != NULL && ++ str_equals_timing_almost_safe(creds->data, str_c(b64_value))) + return TRUE; + + i_error("Invalid authentication attempt to HTTP API " +Index: dovecot/src/doveadm/client-connection-tcp.c +=================================================================== +--- dovecot.orig/src/doveadm/client-connection-tcp.c ++++ dovecot/src/doveadm/client-connection-tcp.c +@@ -342,9 +342,7 @@ client_connection_tcp_authenticate(struc + return -1; + } + pass = t_strndup(data + 9, size - 9); +- if (strlen(pass) != strlen(set->doveadm_password) || +- !mem_equals_timing_safe(pass, set->doveadm_password, +- strlen(pass))) { ++ if (!str_equals_timing_almost_safe(pass, set->doveadm_password)) { + i_error("doveadm client authenticated with wrong password"); + return -1; + } diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27856-2.patch dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27856-2.patch --- dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27856-2.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27856-2.patch 2026-04-03 17:58:21.000000000 +0000 @@ -0,0 +1,51 @@ +From 6d8c50154744284304ceeab69c3951e6d6852007 Mon Sep 17 00:00:00 2001 +From: Aki Tuomi +Date: Wed, 4 Mar 2026 09:28:18 +0200 +Subject: [PATCH 17/24] doveadm: Use datastack for temporary b64 value + +There is no need to allocate it from connection pool. +--- + src/doveadm/client-connection-http.c | 14 +++++--------- + 1 file changed, 5 insertions(+), 9 deletions(-) + +Index: dovecot/src/doveadm/client-connection-http.c +=================================================================== +--- dovecot.orig/src/doveadm/client-connection-http.c ++++ dovecot/src/doveadm/client-connection-http.c +@@ -972,7 +972,7 @@ doveadm_http_server_auth_basic(struct cl + struct client_connection_http *conn = req->conn; + const struct doveadm_settings *set = conn->conn.set; + string_t *b64_value; +- char *value; ++ const char *value; + + if (*set->doveadm_password == '\0') { + i_error("Invalid authentication attempt to HTTP API: " +@@ -980,13 +980,11 @@ doveadm_http_server_auth_basic(struct cl + return FALSE; + } + +- b64_value = str_new(conn->conn.pool, 32); +- value = p_strdup_printf(conn->conn.pool, +- "doveadm:%s", set->doveadm_password); +- base64_encode(value, strlen(value), b64_value); ++ value = t_strdup_printf("doveadm:%s", set->doveadm_password); ++ b64_value = t_base64_encode_str(0, UINT_MAX, value); + + if (creds->data != NULL && +- str_equals_timing_almost_safe(value, creds->data)) ++ str_equals_timing_almost_safe(str_c(b64_value), creds->data)) + return TRUE; + + i_error("Invalid authentication attempt to HTTP API " +@@ -1008,9 +1006,7 @@ doveadm_http_server_auth_api_key(struct + return FALSE; + } + +- b64_value = str_new(conn->conn.pool, 32); +- base64_encode(set->doveadm_api_key, +- strlen(set->doveadm_api_key), b64_value); ++ b64_value = t_base64_encode_str(0, UINT_MAX, set->doveadm_api_key); + if (creds->data != NULL && + str_equals_timing_almost_safe(creds->data, str_c(b64_value))) + return TRUE; diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27856-3.patch dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27856-3.patch --- dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27856-3.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27856-3.patch 2026-04-03 17:58:21.000000000 +0000 @@ -0,0 +1,23 @@ +From cc628976210de17bd26b4d9761ea879ce78b7980 Mon Sep 17 00:00:00 2001 +From: Aki Tuomi +Date: Wed, 4 Mar 2026 14:39:43 +0200 +Subject: [PATCH 18/24] doveadm: client-connection - Get API key from + per-connection settings + +--- + src/doveadm/client-connection-http.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: dovecot/src/doveadm/client-connection-http.c +=================================================================== +--- dovecot.orig/src/doveadm/client-connection-http.c ++++ dovecot/src/doveadm/client-connection-http.c +@@ -997,7 +997,7 @@ doveadm_http_server_auth_api_key(struct + const struct http_auth_credentials *creds) + { + struct client_connection_http *conn = req->conn; +- const struct doveadm_settings *set = doveadm_settings; ++ const struct doveadm_settings *set = conn->conn.set; + string_t *b64_value; + + if (*set->doveadm_api_key == '\0') { diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-1.patch dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-1.patch --- dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-1.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-1.patch 2026-04-03 17:58:21.000000000 +0000 @@ -0,0 +1,24 @@ +From bc91df5f91e8b83c58f138799d39be687271106d Mon Sep 17 00:00:00 2001 +From: Timo Sirainen +Date: Fri, 6 Mar 2026 17:06:45 +0200 +Subject: [PATCH 1/2] plugins: imap-filter-sieve: imap-filter-sieve - Adjust to + imap_parser_create() API change + +--- + src/plugins/imap-filter-sieve/cmd-filter-sieve.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +Index: dovecot/pigeonhole/src/plugins/imap-filter-sieve/cmd-filter-sieve.c +=================================================================== +--- dovecot.orig/pigeonhole/src/plugins/imap-filter-sieve/cmd-filter-sieve.c ++++ dovecot/pigeonhole/src/plugins/imap-filter-sieve/cmd-filter-sieve.c +@@ -379,7 +379,8 @@ bool cmd_filter_sieve(struct client_comm + asynchronously the same way as APPEND does. */ + client->input_lock = cmd; + ctx->parser = imap_parser_create(client->input, client->output, +- client->set->imap_max_line_length); ++ client->set->imap_max_line_length, ++ NULL); + if (client->set->imap_literal_minus) + imap_parser_enable_literal_minus(ctx->parser); + o_stream_unset_flush_callback(client->output); diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-2.patch dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-2.patch --- dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-2.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-2.patch 2026-04-03 17:58:21.000000000 +0000 @@ -0,0 +1,280 @@ +From ad8e6542518acee4e1a803001b232c03732cdaff Mon Sep 17 00:00:00 2001 +From: Timo Sirainen +Date: Fri, 6 Mar 2026 15:25:14 +0200 +Subject: [PATCH 12/24] lib-imap, global: Add params parameter to + imap_parser_create() + +--- + src/imap-login/imap-login-client.c | 4 ++-- + src/imap-login/imap-login-cmd-id.c | 4 +++- + src/imap/cmd-append.c | 3 ++- + src/imap/cmd-setmetadata.c | 3 ++- + src/imap/imap-client.c | 3 ++- + src/lib-imap-client/imapc-connection.c | 3 ++- + src/lib-imap-storage/imap-msgpart.c | 2 +- + src/lib-imap/imap-bodystructure.c | 4 ++-- + src/lib-imap/imap-envelope.c | 2 +- + src/lib-imap/imap-parser.c | 3 ++- + src/lib-imap/imap-parser.h | 6 +++++- + src/lib-imap/test-imap-parser.c | 10 +++++----- + src/plugins/virtual/virtual-config.c | 2 +- + 13 files changed, 30 insertions(+), 19 deletions(-) + +Index: dovecot/src/imap-login/imap-login-client.c +=================================================================== +--- dovecot.orig/src/imap-login/imap-login-client.c ++++ dovecot/src/imap-login/imap-login-client.c +@@ -379,7 +379,7 @@ static void imap_client_create(struct cl + imap_client->parser = + imap_parser_create(imap_client->common.input, + imap_client->common.output, +- IMAP_LOGIN_MAX_LINE_LENGTH); ++ IMAP_LOGIN_MAX_LINE_LENGTH, NULL); + if (imap_client->set->imap_literal_minus) + imap_parser_enable_literal_minus(imap_client->parser); + client->io = io_add_istream(client->input, client_input, client); +@@ -416,7 +416,7 @@ static void imap_client_starttls(struct + imap_client->parser = + imap_parser_create(imap_client->common.input, + imap_client->common.output, +- IMAP_LOGIN_MAX_LINE_LENGTH); ++ IMAP_LOGIN_MAX_LINE_LENGTH, NULL); + + /* CRLF is lost from buffer when streams are reopened. */ + imap_client->skip_line = FALSE; +Index: dovecot/src/imap-login/imap-login-cmd-id.c +=================================================================== +--- dovecot.orig/src/imap-login/imap-login-cmd-id.c ++++ dovecot/src/imap-login/imap-login-cmd-id.c +@@ -237,7 +237,9 @@ int cmd_id(struct imap_client *client) + client->cmd_id = id = i_new(struct imap_client_cmd_id, 1); + id->parser = imap_parser_create(client->common.input, + client->common.output, +- IMAP_LOGIN_MAX_LINE_LENGTH); ++ IMAP_LOGIN_MAX_LINE_LENGTH, ++ NULL); ++ id->log_reply = str_new(default_pool, 64); + if (client->set->imap_literal_minus) + imap_parser_enable_literal_minus(id->parser); + parser_flags = IMAP_PARSE_FLAG_STOP_AT_LIST; +Index: dovecot/src/imap/cmd-append.c +=================================================================== +--- dovecot.orig/src/imap/cmd-append.c ++++ dovecot/src/imap/cmd-append.c +@@ -947,7 +947,8 @@ bool cmd_append(struct client_command_co + o_stream_unset_flush_callback(client->output); + + ctx->save_parser = imap_parser_create(client->input, client->output, +- client->set->imap_max_line_length); ++ client->set->imap_max_line_length, ++ NULL); + if (client->set->imap_literal_minus) + imap_parser_enable_literal_minus(ctx->save_parser); + +Index: dovecot/src/imap/cmd-setmetadata.c +=================================================================== +--- dovecot.orig/src/imap/cmd-setmetadata.c ++++ dovecot/src/imap/cmd-setmetadata.c +@@ -289,7 +289,8 @@ cmd_setmetadata_start(struct imap_setmet + asynchronously the same way as APPEND does. */ + client->input_lock = cmd; + ctx->parser = imap_parser_create(client->input, client->output, +- client->set->imap_max_line_length); ++ client->set->imap_max_line_length, ++ NULL); + if (client->set->imap_literal_minus) + imap_parser_enable_literal_minus(ctx->parser); + o_stream_unset_flush_callback(client->output); +Index: dovecot/src/imap/imap-client.c +=================================================================== +--- dovecot.orig/src/imap/imap-client.c ++++ dovecot/src/imap/imap-client.c +@@ -953,7 +953,8 @@ client_command_new(struct client *client + } else { + cmd->parser = + imap_parser_create(client->input, client->output, +- client->set->imap_max_line_length); ++ client->set->imap_max_line_length, ++ NULL); + if (client->set->imap_literal_minus) + imap_parser_enable_literal_minus(cmd->parser); + } +Index: dovecot/src/lib-imap-client/imapc-connection.c +=================================================================== +--- dovecot.orig/src/lib-imap-client/imapc-connection.c ++++ dovecot/src/lib-imap-client/imapc-connection.c +@@ -1822,7 +1822,8 @@ static void imapc_connection_connect_nex + o_stream_set_flush_callback(conn->output, imapc_connection_connected, + conn); + conn->parser = imap_parser_create(conn->input, NULL, +- conn->client->set.max_line_length); ++ conn->client->set.max_line_length, ++ NULL); + conn->to = timeout_add(conn->client->set.connect_timeout_msecs, + imapc_connection_timeout, conn); + conn->to_output = timeout_add(conn->client->set.max_idle_time*1000, +Index: dovecot/src/lib-imap-storage/imap-msgpart.c +=================================================================== +--- dovecot.orig/src/lib-imap-storage/imap-msgpart.c ++++ dovecot/src/lib-imap-storage/imap-msgpart.c +@@ -148,7 +148,7 @@ imap_msgpart_get_header_fields(pool_t po + int result = 0; + + input = i_stream_create_from_data(header_list, strlen(header_list)); +- parser = imap_parser_create(input, NULL, SIZE_MAX); ++ parser = imap_parser_create(input, NULL, SIZE_MAX, NULL); + + if (imap_parser_finish_line(parser, 0, 0, &args) > 0 && + imap_arg_get_list_full(args, &hdr_list, &list_count) && +Index: dovecot/src/lib-imap/imap-bodystructure.c +=================================================================== +--- dovecot.orig/src/lib-imap/imap-bodystructure.c ++++ dovecot/src/lib-imap/imap-bodystructure.c +@@ -694,7 +694,7 @@ int imap_bodystructure_parse_full(const + input = i_stream_create_from_data(bodystructure, strlen(bodystructure)); + (void)i_stream_read(input); + +- parser = imap_parser_create(input, NULL, SIZE_MAX); ++ parser = imap_parser_create(input, NULL, SIZE_MAX, NULL); + ret = imap_parser_finish_line(parser, 0, + IMAP_PARSE_FLAG_LITERAL_TYPE, &args); + if (ret < 0) { +@@ -937,7 +937,7 @@ int imap_body_parse_from_bodystructure(c + input = i_stream_create_from_data(bodystructure, strlen(bodystructure)); + (void)i_stream_read(input); + +- parser = imap_parser_create(input, NULL, SIZE_MAX); ++ parser = imap_parser_create(input, NULL, SIZE_MAX, NULL); + ret = imap_parser_finish_line(parser, 0, IMAP_PARSE_FLAG_NO_UNESCAPE | + IMAP_PARSE_FLAG_LITERAL_TYPE, &args); + if (ret < 0) { +Index: dovecot/src/lib-imap/imap-envelope.c +=================================================================== +--- dovecot.orig/src/lib-imap/imap-envelope.c ++++ dovecot/src/lib-imap/imap-envelope.c +@@ -222,7 +222,7 @@ bool imap_envelope_parse(const char *env + input = i_stream_create_from_data(envelope, strlen(envelope)); + (void)i_stream_read(input); + +- parser = imap_parser_create(input, NULL, SIZE_MAX); ++ parser = imap_parser_create(input, NULL, SIZE_MAX, NULL); + ret = imap_parser_finish_line(parser, 0, + IMAP_PARSE_FLAG_LITERAL_TYPE, &args); + if (ret < 0) { +Index: dovecot/src/lib-imap/imap-parser.c +=================================================================== +--- dovecot.orig/src/lib-imap/imap-parser.c ++++ dovecot/src/lib-imap/imap-parser.c +@@ -69,7 +69,8 @@ struct imap_parser { + + struct imap_parser * + imap_parser_create(struct istream *input, struct ostream *output, +- size_t max_line_size) ++ size_t max_line_size, ++ const struct imap_parser_params *params ATTR_UNUSED) + { + struct imap_parser *parser; + +Index: dovecot/src/lib-imap/imap-parser.h +=================================================================== +--- dovecot.orig/src/lib-imap/imap-parser.h ++++ dovecot/src/lib-imap/imap-parser.h +@@ -38,6 +38,9 @@ enum imap_parser_error { + IMAP_PARSE_ERROR_LITERAL_TOO_BIG + }; + ++struct imap_parser_params { ++}; ++ + struct imap_parser; + + /* Create new IMAP argument parser. output is used for sending command +@@ -53,7 +56,8 @@ struct imap_parser; + 2 * max_line_size. */ + struct imap_parser * + imap_parser_create(struct istream *input, struct ostream *output, +- size_t max_line_size) ATTR_NULL(2); ++ size_t max_line_size, ++ const struct imap_parser_params *params); + void imap_parser_ref(struct imap_parser *parser); + void imap_parser_unref(struct imap_parser **parser); + +Index: dovecot/src/lib-imap/test-imap-parser.c +=================================================================== +--- dovecot.orig/src/lib-imap/test-imap-parser.c ++++ dovecot/src/lib-imap/test-imap-parser.c +@@ -16,7 +16,7 @@ static void test_imap_parser_crlf(void) + + test_begin("imap parser crlf handling"); + input = test_istream_create(test_input); +- parser = imap_parser_create(input, NULL, 1024); ++ parser = imap_parser_create(input, NULL, 1024, NULL); + + /* must return -2 until LF is read */ + for (i = 0; test_input[i] != '\n'; i++) { +@@ -60,7 +60,7 @@ static void test_imap_parser_partial_lis + + test_begin("imap parser partial list"); + input = test_istream_create(test_input); +- parser = imap_parser_create(input, NULL, 1024); ++ parser = imap_parser_create(input, NULL, 1024, NULL); + + (void)i_stream_read(input); + test_assert(imap_parser_read_args(parser, 0, +@@ -123,7 +123,7 @@ static void test_imap_parser_read_tag_cm + if (tests[i].type != COMMAND) { + input = test_istream_create(tests[i].input); + test_assert(i_stream_read(input) > 0); +- parser = imap_parser_create(input, NULL, 1024); ++ parser = imap_parser_create(input, NULL, 1024, NULL); + ret = imap_parser_read_tag(parser, &atom); + test_assert_idx(ret == tests[i].ret, i); + test_assert_idx(ret <= 0 || strcmp(tests[i].tag, atom) == 0, i); +@@ -134,7 +134,7 @@ static void test_imap_parser_read_tag_cm + if (tests[i].type != TAG) { + input = test_istream_create(tests[i].input); + test_assert(i_stream_read(input) > 0); +- parser = imap_parser_create(input, NULL, 1024); ++ parser = imap_parser_create(input, NULL, 1024, NULL); + ret = imap_parser_read_command_name(parser, &atom); + test_assert_idx(ret == tests[i].ret, i); + test_assert_idx(ret <= 0 || strcmp(tests[i].tag, atom) == 0, i); +Index: dovecot/src/plugins/virtual/virtual-config.c +=================================================================== +--- dovecot.orig/src/plugins/virtual/virtual-config.c ++++ dovecot/src/plugins/virtual/virtual-config.c +@@ -54,7 +54,7 @@ virtual_search_args_parse(const string_t + input = i_stream_create_from_data(str_data(rule), str_len(rule)); + (void)i_stream_read(input); + +- imap_parser = imap_parser_create(input, NULL, SIZE_MAX); ++ imap_parser = imap_parser_create(input, NULL, SIZE_MAX, NULL); + ret = imap_parser_finish_line(imap_parser, 0, 0, &args); + if (ret < 0) { + sargs = NULL; +Index: dovecot/src/lib-imap/imap-id.c +=================================================================== +--- dovecot.orig/src/lib-imap/imap-id.c ++++ dovecot/src/lib-imap/imap-id.c +@@ -111,7 +111,7 @@ const char *imap_id_reply_generate(const + input = i_stream_create_from_data(settings, strlen(settings)); + (void)i_stream_read(input); + +- parser = imap_parser_create(input, NULL, SIZE_MAX); ++ parser = imap_parser_create(input, NULL, SIZE_MAX, NULL); + if (imap_parser_finish_line(parser, 0, 0, &args) <= 0) + ret = "NIL"; + else +Index: dovecot/src/director/director-test.c +=================================================================== +--- dovecot.orig/src/director/director-test.c ++++ dovecot/src/director/director-test.c +@@ -250,7 +250,7 @@ static void imap_client_create(int fd) + o_stream_set_no_error_handling(client->output, TRUE); + client->io = io_add(fd, IO_READ, imap_client_input, client); + client->parser = +- imap_parser_create(client->input, client->output, 4096); ++ imap_parser_create(client->input, client->output, 4096, NULL); + o_stream_nsend_str(client->output, + "* OK [CAPABILITY IMAP4rev1] director-test ready.\r\n"); + DLLIST_PREPEND(&imap_clients, client); diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-3.patch dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-3.patch --- dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-3.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-3.patch 2026-04-03 17:58:21.000000000 +0000 @@ -0,0 +1,160 @@ +From bb845a61f81be978f641b79058d4bae06f27ee39 Mon Sep 17 00:00:00 2001 +From: Timo Sirainen +Date: Fri, 6 Mar 2026 15:32:29 +0200 +Subject: [PATCH 13/24] lib-imap: Add imap_parser_params.list_count_limit + +--- + src/lib-imap/imap-parser.c | 15 ++++++++++- + src/lib-imap/imap-parser.h | 6 +++++ + src/lib-imap/test-imap-parser.c | 46 +++++++++++++++++++++++++++++++++ + 3 files changed, 66 insertions(+), 1 deletion(-) + +Index: dovecot/src/lib-imap/imap-parser.c +=================================================================== +--- dovecot.orig/src/lib-imap/imap-parser.c ++++ dovecot/src/lib-imap/imap-parser.c +@@ -39,6 +39,7 @@ struct imap_parser { + struct istream *input; + struct ostream *output; + size_t max_line_size; ++ unsigned int list_count_limit; + enum imap_parser_flags flags; + + /* reset by imap_parser_reset(): */ +@@ -46,6 +47,7 @@ struct imap_parser { + ARRAY_TYPE(imap_arg_list) root_list; + ARRAY_TYPE(imap_arg_list) *cur_list; + struct imap_arg *list_arg; ++ unsigned int list_count; + + enum arg_parse_type cur_type; + size_t cur_pos; /* parser position in input buffer */ +@@ -70,7 +72,7 @@ struct imap_parser { + struct imap_parser * + imap_parser_create(struct istream *input, struct ostream *output, + size_t max_line_size, +- const struct imap_parser_params *params ATTR_UNUSED) ++ const struct imap_parser_params *params) + { + struct imap_parser *parser; + +@@ -81,6 +83,10 @@ imap_parser_create(struct istream *input + parser->input = input; + parser->output = output; + parser->max_line_size = max_line_size; ++ if (params != NULL && params->list_count_limit > 0) ++ parser->list_count_limit = params->list_count_limit; ++ else ++ parser->list_count_limit = UINT_MAX; + + p_array_init(&parser->root_list, parser->pool, LIST_INIT_COUNT); + parser->cur_list = &parser->root_list; +@@ -122,6 +128,7 @@ void imap_parser_reset(struct imap_parse + p_array_init(&parser->root_list, parser->pool, LIST_INIT_COUNT); + parser->cur_list = &parser->root_list; + parser->list_arg = NULL; ++ parser->list_count = 0; + + parser->cur_type = ARG_PARSE_NONE; + parser->cur_pos = 0; +@@ -210,6 +217,12 @@ static bool imap_parser_close_list(struc + parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX; + return FALSE; + } ++ if (parser->list_count >= parser->list_count_limit) { ++ parser->error_msg = "Too many '('"; ++ parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX; ++ return FALSE; ++ } ++ parser->list_count++; + + arg = imap_arg_create(parser); + arg->type = IMAP_ARG_EOL; +Index: dovecot/src/lib-imap/imap-parser.h +=================================================================== +--- dovecot.orig/src/lib-imap/imap-parser.h ++++ dovecot/src/lib-imap/imap-parser.h +@@ -39,6 +39,12 @@ enum imap_parser_error { + }; + + struct imap_parser_params { ++ /* How many open lists ('(' chars) to allow before faililng the parsing. ++ 0 means unlimited. This is mainly used to prevent excessive memory ++ usage in imap-login process. In imap process there are many other ++ ways to increase memory usage, so we let the max_line_size be the ++ only limit. */ ++ unsigned int list_count_limit; + }; + + struct imap_parser; +Index: dovecot/src/lib-imap/test-imap-parser.c +=================================================================== +--- dovecot.orig/src/lib-imap/test-imap-parser.c ++++ dovecot/src/lib-imap/test-imap-parser.c +@@ -2,6 +2,7 @@ + + #include "lib.h" + #include "istream.h" ++#include "istream-chain.h" + #include "imap-parser.h" + #include "test-common.h" + +@@ -79,6 +80,50 @@ static void test_imap_parser_partial_lis + test_end(); + } + ++static void test_imap_parser_list_limit(void) ++{ ++ struct { ++ const char *input; ++ int ret; ++ } tests[] = { ++ { "(())\r\n", 1 }, ++ { "((()))\r\n", -1 }, ++ }; ++ struct istream_chain *chain; ++ struct istream *chain_input; ++ struct imap_parser *parser; ++ const struct imap_arg *args; ++ ++ test_begin("imap parser list limit"); ++ struct imap_parser_params params = { ++ .list_count_limit = 2, ++ }; ++ ++ for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) { ++ chain_input = i_stream_create_chain(&chain, IO_BLOCK_SIZE); ++ parser = imap_parser_create(chain_input, NULL, 1024, ¶ms); ++ ++ for (unsigned int j = 0; j < 2; j++) { ++ struct istream *input = ++ test_istream_create(tests[i].input); ++ i_stream_chain_append(chain, input); ++ i_stream_unref(&input); ++ ++ (void)i_stream_read(chain_input); ++ ++ test_assert_cmp(imap_parser_read_args(parser, 0, 0, &args), ==, tests[i].ret); ++ /* skip over CRLF */ ++ i_stream_skip(chain_input, i_stream_get_data_size(chain_input)); ++ ++ /* make sure parser reset works */ ++ imap_parser_reset(parser); ++ } ++ imap_parser_unref(&parser); ++ i_stream_destroy(&chain_input); ++ } ++ test_end(); ++} ++ + static void test_imap_parser_read_tag_cmd(void) + { + enum read_type { +@@ -150,6 +195,7 @@ int main(void) + static void (*const test_functions[])(void) = { + test_imap_parser_crlf, + test_imap_parser_partial_list, ++ test_imap_parser_list_limit, + test_imap_parser_read_tag_cmd, + NULL + }; diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-4.patch dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-4.patch --- dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-4.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-4.patch 2026-04-03 17:58:21.000000000 +0000 @@ -0,0 +1,84 @@ +From ab084588f615b7f2bb6e18c8ee9176511b647aca Mon Sep 17 00:00:00 2001 +From: Timo Sirainen +Date: Fri, 6 Mar 2026 15:35:12 +0200 +Subject: [PATCH 14/24] imap-login: Limit the number of open IMAP parser lists + +This prevents attackers from using a large number of '(' in a command to +grow memory usage excessively. +--- + src/imap-login/imap-login-client.c | 10 ++++++++-- + src/imap-login/imap-login-client.h | 4 ++++ + src/imap-login/imap-login-cmd-id.c | 6 +++++- + 3 files changed, 17 insertions(+), 3 deletions(-) + +Index: dovecot/src/imap-login/imap-login-client.c +=================================================================== +--- dovecot.orig/src/imap-login/imap-login-client.c ++++ dovecot/src/imap-login/imap-login-client.c +@@ -375,11 +375,14 @@ static void imap_client_create(struct cl + { + struct imap_client *imap_client = (struct imap_client *)client; + ++ struct imap_parser_params params = { ++ .list_count_limit = IMAP_LOGIN_LIST_COUNT_LIMIT, ++ }; + imap_client->set = other_sets[0]; + imap_client->parser = + imap_parser_create(imap_client->common.input, + imap_client->common.output, +- IMAP_LOGIN_MAX_LINE_LENGTH, NULL); ++ IMAP_LOGIN_MAX_LINE_LENGTH, ¶ms); + if (imap_client->set->imap_literal_minus) + imap_parser_enable_literal_minus(imap_client->parser); + client->io = io_add_istream(client->input, client_input, client); +@@ -412,11 +415,14 @@ static void imap_client_starttls(struct + { + struct imap_client *imap_client = (struct imap_client *)client; + ++ struct imap_parser_params params = { ++ .list_count_limit = IMAP_LOGIN_LIST_COUNT_LIMIT, ++ }; + imap_parser_unref(&imap_client->parser); + imap_client->parser = + imap_parser_create(imap_client->common.input, + imap_client->common.output, +- IMAP_LOGIN_MAX_LINE_LENGTH, NULL); ++ IMAP_LOGIN_MAX_LINE_LENGTH, ¶ms); + + /* CRLF is lost from buffer when streams are reopened. */ + imap_client->skip_line = FALSE; +Index: dovecot/src/imap-login/imap-login-client.h +=================================================================== +--- dovecot.orig/src/imap-login/imap-login-client.h ++++ dovecot/src/imap-login/imap-login-client.h +@@ -11,6 +11,10 @@ + /* maximum length for IMAP command line. */ + #define IMAP_LOGIN_MAX_LINE_LENGTH 8192 + ++/* Maximum number of '(' allowed in an IMAP command. Pre-login only uses ++ lists in the ID command. */ ++#define IMAP_LOGIN_LIST_COUNT_LIMIT 1 ++ + enum imap_client_id_state { + IMAP_CLIENT_ID_STATE_LIST = 0, + IMAP_CLIENT_ID_STATE_KEY, +Index: dovecot/src/imap-login/imap-login-cmd-id.c +=================================================================== +--- dovecot.orig/src/imap-login/imap-login-cmd-id.c ++++ dovecot/src/imap-login/imap-login-cmd-id.c +@@ -235,10 +235,14 @@ int cmd_id(struct imap_client *client) + + if (client->cmd_id == NULL) { + client->cmd_id = id = i_new(struct imap_client_cmd_id, 1); ++ ++ struct imap_parser_params params = { ++ .list_count_limit = IMAP_LOGIN_LIST_COUNT_LIMIT, ++ }; + id->parser = imap_parser_create(client->common.input, + client->common.output, + IMAP_LOGIN_MAX_LINE_LENGTH, +- NULL); ++ ¶ms); + id->log_reply = str_new(default_pool, 64); + if (client->set->imap_literal_minus) + imap_parser_enable_literal_minus(id->parser); diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-5.patch dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-5.patch --- dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-5.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27857-5.patch 2026-04-03 17:58:21.000000000 +0000 @@ -0,0 +1,59 @@ +From e0b953af76d754c2984c2867b71fccfef5231bf5 Mon Sep 17 00:00:00 2001 +From: Timo Sirainen +Date: Mon, 2 Mar 2026 13:50:24 +0200 +Subject: [PATCH 15/24] global: Use const for struct imap_parser_params params + +--- + src/imap-login/imap-login-client.c | 4 ++-- + src/imap-login/imap-login-cmd-id.c | 2 +- + src/lib-imap/test-imap-parser.c | 2 +- + 3 files changed, 4 insertions(+), 4 deletions(-) + +Index: dovecot/src/imap-login/imap-login-client.c +=================================================================== +--- dovecot.orig/src/imap-login/imap-login-client.c ++++ dovecot/src/imap-login/imap-login-client.c +@@ -375,7 +375,7 @@ static void imap_client_create(struct cl + { + struct imap_client *imap_client = (struct imap_client *)client; + +- struct imap_parser_params params = { ++ const struct imap_parser_params params = { + .list_count_limit = IMAP_LOGIN_LIST_COUNT_LIMIT, + }; + imap_client->set = other_sets[0]; +@@ -415,7 +415,7 @@ static void imap_client_starttls(struct + { + struct imap_client *imap_client = (struct imap_client *)client; + +- struct imap_parser_params params = { ++ const struct imap_parser_params params = { + .list_count_limit = IMAP_LOGIN_LIST_COUNT_LIMIT, + }; + imap_parser_unref(&imap_client->parser); +Index: dovecot/src/imap-login/imap-login-cmd-id.c +=================================================================== +--- dovecot.orig/src/imap-login/imap-login-cmd-id.c ++++ dovecot/src/imap-login/imap-login-cmd-id.c +@@ -236,7 +236,7 @@ int cmd_id(struct imap_client *client) + if (client->cmd_id == NULL) { + client->cmd_id = id = i_new(struct imap_client_cmd_id, 1); + +- struct imap_parser_params params = { ++ const struct imap_parser_params params = { + .list_count_limit = IMAP_LOGIN_LIST_COUNT_LIMIT, + }; + id->parser = imap_parser_create(client->common.input, +Index: dovecot/src/lib-imap/test-imap-parser.c +=================================================================== +--- dovecot.orig/src/lib-imap/test-imap-parser.c ++++ dovecot/src/lib-imap/test-imap-parser.c +@@ -95,7 +95,7 @@ static void test_imap_parser_list_limit( + const struct imap_arg *args; + + test_begin("imap parser list limit"); +- struct imap_parser_params params = { ++ const struct imap_parser_params params = { + .list_count_limit = 2, + }; + diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27858.patch dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27858.patch --- dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27858.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27858.patch 2026-04-03 17:58:21.000000000 +0000 @@ -0,0 +1,28 @@ +From fcb339d39bfb19abf1bb88711112f49c1c589b1a Mon Sep 17 00:00:00 2001 +From: Timo Sirainen +Date: Mon, 2 Mar 2026 14:40:57 +0200 +Subject: [PATCH 2/2] managesieve-login: Verify AUTHENTICATE initial response + size isn't too large + +This prevents DoSing the managesieve-login by sending an excessively large +initial response size, which causes a huge memory allocation. +--- + src/managesieve-login/client-authenticate.c | 5 +++++ + 1 file changed, 5 insertions(+) + +Index: dovecot/pigeonhole/src/managesieve-login/client-authenticate.c +=================================================================== +--- dovecot.orig/pigeonhole/src/managesieve-login/client-authenticate.c ++++ dovecot/pigeonhole/src/managesieve-login/client-authenticate.c +@@ -189,6 +189,11 @@ static int managesieve_client_auth_read_ + if ( i_stream_get_size + (msieve_client->auth_response_input, FALSE, &resp_size) <= 0 ) + resp_size = 0; ++ else if (resp_size > LOGIN_MAX_AUTH_BUF_SIZE) { ++ client_destroy(client, ++ "Authentication response too large"); ++ return -1; ++ } + + if (client->auth_response == NULL) + client->auth_response = str_new(default_pool, I_MAX(resp_size+1, 256)); diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27859.patch dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27859.patch --- dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27859.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/CVE-2026-27859.patch 2026-04-03 17:58:21.000000000 +0000 @@ -0,0 +1,103 @@ +From 4041a0cb7bbaa6faf38670ab92afc1039dd0d0d5 Mon Sep 17 00:00:00 2001 +From: Timo Sirainen +Date: Tue, 24 Feb 2026 13:11:14 +0200 +Subject: [PATCH 03/24] lib-mail: Limit the number of RFC2231 parameters that + can be parsed + +This avoids excessive CPU usage especially in result_append(). +--- + src/lib-mail/rfc2231-parser.c | 4 +++- + src/lib-mail/rfc822-parser.h | 5 +++++ + src/lib-mail/test-rfc2231-parser.c | 30 ++++++++++++++++++++++++++++++ + 3 files changed, 38 insertions(+), 1 deletion(-) + +Index: dovecot/src/lib-mail/rfc2231-parser.c +=================================================================== +--- dovecot.orig/src/lib-mail/rfc2231-parser.c ++++ dovecot/src/lib-mail/rfc2231-parser.c +@@ -45,7 +45,7 @@ int rfc2231_parse(struct rfc822_parser_c + const struct rfc2231_parameter *rfc2231_params; + const char *key, *p, *p2; + string_t *str; +- unsigned int i, j, count, next, next_idx; ++ unsigned int i, j, count, next, next_idx, params_count = 0; + bool ok, have_extended, broken = FALSE; + const char *prev_replacement_str; + int ret; +@@ -63,6 +63,8 @@ int rfc2231_parse(struct rfc822_parser_c + t_array_init(&rfc2231_params_arr, 8); + str = t_str_new(64); + while ((ret = rfc822_parse_content_param(ctx, &key, str)) != 0) { ++ if (++params_count > RFC2231_MAX_PARAMS) ++ break; + if (ret < 0) { + /* try to continue anyway.. */ + broken = TRUE; +Index: dovecot/src/lib-mail/rfc822-parser.h +=================================================================== +--- dovecot.orig/src/lib-mail/rfc822-parser.h ++++ dovecot/src/lib-mail/rfc822-parser.h +@@ -3,6 +3,11 @@ + + #include "unichar.h" + ++/* Maximum number of parameters to parse. After this the rest of the parameters ++ are skipped. This is to avoid excessive CPU usage that can be caused by ++ merging of these parameters. */ ++#define RFC2231_MAX_PARAMS 128 ++ + /* This can be used as a common NUL replacement character */ + #define RFC822_NUL_REPLACEMENT_STR UNICODE_REPLACEMENT_CHAR_UTF8 + +Index: dovecot/src/lib-mail/test-rfc2231-parser.c +=================================================================== +--- dovecot.orig/src/lib-mail/test-rfc2231-parser.c ++++ dovecot/src/lib-mail/test-rfc2231-parser.c +@@ -1,6 +1,7 @@ + /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */ + + #include "lib.h" ++#include "str.h" + #include "rfc822-parser.h" + #include "rfc2231-parser.h" + #include "test-common.h" +@@ -41,10 +42,39 @@ static void test_rfc2231_parser(void) + test_end(); + } + ++static void test_rfc2231_parser_limits(void) ++{ ++ string_t *input = t_str_new(1024); ++ ++ test_begin("rfc2231 parser limits"); ++ str_append(input, "; "); ++ for (unsigned int i = 0; i < 1100; i++) ++ str_printfa(input, "a%u=b%u; ", i, i); ++ struct rfc822_parser_context parser; ++ const char *const *result; ++ rfc822_parser_init(&parser, str_data(input), str_len(input), NULL); ++ test_assert(rfc2231_parse(&parser, &result) == 0); ++ ++ unsigned int count = str_array_length(result); ++ test_assert(count == RFC2231_MAX_PARAMS * 2); ++ for (unsigned int i = 0; i < count; i += 2) { ++ str_truncate(input, 0); ++ str_printfa(input, "a%u", i / 2); ++ test_assert_strcmp_idx(result[i], str_c(input), i); ++ ++ str_truncate(input, 0); ++ str_printfa(input, "b%u", i / 2); ++ test_assert_strcmp_idx(result[i + 1], str_c(input), i); ++ } ++ rfc822_parser_deinit(&parser); ++ test_end(); ++} ++ + int main(void) + { + static void (*const test_functions[])(void) = { + test_rfc2231_parser, ++ test_rfc2231_parser_limits, + NULL + }; + return test_run(test_functions); diff -Nru dovecot-2.3.19.1+dfsg1/debian/patches/series dovecot-2.3.19.1+dfsg1/debian/patches/series --- dovecot-2.3.19.1+dfsg1/debian/patches/series 2024-08-18 14:25:33.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/patches/series 2026-04-03 17:58:21.000000000 +0000 @@ -22,3 +22,21 @@ Fix-uninitialized-read-in-doveadm-oldstats.patch CVE-2024-23184.patch CVE-2024-23185.patch +CVE-2025-59031.patch +CVE-2025-59032.patch +CVE-2026-0394-1.patch +CVE-2026-0394-2.patch +CVE-2026-27855-1.patch +CVE-2026-27855-2.patch +CVE-2026-27855-3.patch +CVE-2026-27855-4.patch +CVE-2026-27856-1.patch +CVE-2026-27856-2.patch +CVE-2026-27856-3.patch +CVE-2026-27857-1.patch +CVE-2026-27857-2.patch +CVE-2026-27857-3.patch +CVE-2026-27857-4.patch +CVE-2026-27857-5.patch +CVE-2026-27858.patch +CVE-2026-27859.patch diff -Nru dovecot-2.3.19.1+dfsg1/debian/rules dovecot-2.3.19.1+dfsg1/debian/rules --- dovecot-2.3.19.1+dfsg1/debian/rules 2024-08-18 14:25:33.000000000 +0000 +++ dovecot-2.3.19.1+dfsg1/debian/rules 2026-04-03 17:58:21.000000000 +0000 @@ -159,7 +159,6 @@ $(MAKE) -C $(PIGEONHOLE_DIR) install DESTDIR=$(CORE_DIR) rm `find $(CURDIR)/debian -name '*.la'` rm $(CORE_DIR)/etc/dovecot/README - rm $(CORE_DIR)/usr/lib/dovecot/decode2text.sh override_dh_install: # dh_auto_install has installed everything in the dovecot-core package.