This patch fixes following issues:
VUL-0: CVE-2025-59032: dovecot: pigeonhole: ManageSieve panic occurs with sieve-connect as a client
VUL-0: CVE-2026-27858: dovecot: pigeonhole: managesieve-login can allocate large amount of memory during authentication.
VUL-0: CVE-2026-27855: dovecot: OTP driver vulnerable to replay attack
VUL-0: CVE-2026-27856: dovecot: Doveadm credentials were not checked using timing-safe checking function
VUL-0: CVE-2026-27857: dovecot: sending excessive parenthesis causes imap-login to use excessive memory
VUL-0: CVE-2026-27859: dovecot: excessive RFC 2231 MIME parameters in email would can excessive CPU usage
VUL-0: CVE-2025-59031: dovecot: decode2text.sh OOXML extraction may follow symlinks and read unintended files during indexing
diff -rup dovecot-2.2.31-orig/dovecot-2.2-pigeonhole-0.4.19/src/lib-managesieve/managesieve-parser.c dovecot-2.2.31/dovecot-2.2-pigeonhole-0.4.19/src/lib-managesieve/managesieve-parser.c
--- dovecot-2.2.31-orig/dovecot-2.2-pigeonhole-0.4.19/src/lib-managesieve/managesieve-parser.c	2026-04-09 18:24:18.064191606 +0200
+++ dovecot-2.2.31/dovecot-2.2-pigeonhole-0.4.19/src/lib-managesieve/managesieve-parser.c	2026-04-09 19:37:35.720965174 +0200
@@ -694,7 +694,7 @@ static ssize_t quoted_string_istream_rea
 			slash = FALSE;
 		}
 
-		if ( (data[i] & 0x80) == 0 && ( data[i] == '\r' || data[i] == '\n' ) ) {
+		if ( (data[i] & 0x80) == 0 && ( data[i] == '\r' || data[i] == '\n' || data[i] == '\0' ) ) {
 			io_stream_set_error(&stream->iostream,
 				"Quoted string contains an invalid character");
 			stream->istream.stream_errno = EINVAL;
Nur in dovecot-2.2.31-orig/dovecot-2.2-pigeonhole-0.4.19/src/lib-managesieve: managesieve-parser.c.orig.
diff -rup dovecot-2.2.31-orig/dovecot-2.2-pigeonhole-0.4.19/src/managesieve-login/client-authenticate.c dovecot-2.2.31/dovecot-2.2-pigeonhole-0.4.19/src/managesieve-login/client-authenticate.c
--- dovecot-2.2.31-orig/dovecot-2.2-pigeonhole-0.4.19/src/managesieve-login/client-authenticate.c	2017-05-24 16:59:30.000000000 +0200
+++ dovecot-2.2.31/dovecot-2.2-pigeonhole-0.4.19/src/managesieve-login/client-authenticate.c	2026-04-09 19:45:06.640748939 +0200
@@ -196,6 +196,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 -rup dovecot-2.2.31-orig/dovecot-2.2-pigeonhole-0.4.19/src/managesieve-login/client.c dovecot-2.2.31/dovecot-2.2-pigeonhole-0.4.19/src/managesieve-login/client.c
--- dovecot-2.2.31-orig/dovecot-2.2-pigeonhole-0.4.19/src/managesieve-login/client.c	2026-04-09 18:24:18.048191472 +0200
+++ dovecot-2.2.31/dovecot-2.2-pigeonhole-0.4.19/src/managesieve-login/client.c	2026-04-09 19:40:41.462522566 +0200
@@ -301,10 +301,12 @@ static bool managesieve_client_input_nex
 			if ( args[0].type != MANAGESIEVE_ARG_EOL )
 				ret = -1;
 		}
-	}
-	if (ret > 0) {
+		if (ret > 0)
+			ret = client->cmd->func(client, args);
+	} else {
+		/* Continue unfinished command */
 		i_assert(client->cmd != NULL);
-		ret = client->cmd->func(client, args);
+		ret = client->cmd->func(client, NULL);
 	}
 
 	if (ret != 0)
Nur in dovecot-2.2.31-orig/src/auth: auth-request.c.orig.
Nur in dovecot-2.2.31-orig/src/auth: auth-request-handler.c.orig.
diff -rup dovecot-2.2.31-orig/src/auth/mech-otp.c dovecot-2.2.31/src/auth/mech-otp.c
--- dovecot-2.2.31-orig/src/auth/mech-otp.c	2017-06-26 13:29:01.000000000 +0200
+++ dovecot-2.2.31/src/auth/mech-otp.c	2026-04-09 19:49:27.730941216 +0200
@@ -150,8 +150,7 @@ static void mech_otp_verify(struct auth_
 
 	otp_next_hash(state->algo, hash, cur_hash);
 
-	ret = memcmp(cur_hash, state->hash, OTP_HASH_SIZE);
-	if (ret != 0) {
+	if (!mem_equals_timing_safe(cur_hash, state->hash, OTP_HASH_SIZE)) {
 		auth_request_fail(auth_request);
 		otp_unlock(auth_request);
 		return;
@@ -185,8 +184,7 @@ static void mech_otp_verify_init(struct
 
 	otp_next_hash(request->state.algo, cur_hash, hash);
 
-	ret = memcmp(hash, request->state.hash, OTP_HASH_SIZE);
-	if (ret != 0) {
+	if (!mem_equals_timing_safe(hash, request->state.hash, OTP_HASH_SIZE)) {
 		auth_request_fail(auth_request);
 		otp_unlock(auth_request);
 		return;
Nur in dovecot-2.2.31-orig/src/config: config-connection.c.orig.
diff -rup dovecot-2.2.31-orig/src/director/director-test.c dovecot-2.2.31/src/director/director-test.c
--- dovecot-2.2.31-orig/src/director/director-test.c	2017-06-26 13:29:36.000000000 +0200
+++ dovecot-2.2.31/src/director/director-test.c	2026-04-09 20:18:20.457540736 +0200
@@ -251,7 +251,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 -rup dovecot-2.2.31-orig/src/doveadm/client-connection-http.c dovecot-2.2.31/src/doveadm/client-connection-http.c
--- dovecot-2.2.31-orig/src/doveadm/client-connection-http.c	2017-06-26 13:29:36.000000000 +0200
+++ dovecot-2.2.31/src/doveadm/client-connection-http.c	2026-04-11 07:02:40.407279295 +0200
@@ -664,13 +664,13 @@ doveadm_http_server_authorize_request(st
 			string_t *b64_value = str_new(conn->client.pool, 32);
 			char *value = p_strdup_printf(conn->client.pool, "doveadm:%s", conn->client.set->doveadm_password);
 			base64_encode(value, strlen(value), b64_value);
-			if (creds.data != NULL && strcmp(creds.data, str_c(b64_value)) == 0) auth = TRUE;
+			if (creds.data != NULL && str_equals_timing_almost_safe(value, creds.data)) auth = TRUE;
 			else i_error("Invalid authentication attempt to HTTP API");
 		}
 		else if (strcasecmp(creds.scheme, "X-Dovecot-API") == 0 && doveadm_settings->doveadm_api_key[0] != '\0') {
 			string_t *b64_value = str_new(conn->client.pool, 32);
 			base64_encode(doveadm_settings->doveadm_api_key, strlen(doveadm_settings->doveadm_api_key), b64_value);
-			if (creds.data != NULL && strcmp(creds.data, str_c(b64_value)) == 0) auth = TRUE;
+			if (creds.data != NULL && str_equals_timing_almost_safe(b64_value, creds.data)) auth = TRUE;
 			else i_error("Invalid authentication attempt to HTTP API");
 		}
 		else i_error("Unsupported authentication scheme to HTTP API");
diff -rup dovecot-2.2.31-orig/src/imap/cmd-append.c dovecot-2.2.31/src/imap/cmd-append.c
--- dovecot-2.2.31-orig/src/imap/cmd-append.c	2017-06-26 13:29:36.000000000 +0200
+++ dovecot-2.2.31/src/imap/cmd-append.c	2026-04-09 20:18:58.321860180 +0200
@@ -922,7 +922,7 @@ 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);
 
 	cmd->func = cmd_append_parse_new_msg;
 	cmd->context = ctx;
diff -rup dovecot-2.2.31-orig/src/imap/cmd-setmetadata.c dovecot-2.2.31/src/imap/cmd-setmetadata.c
--- dovecot-2.2.31-orig/src/imap/cmd-setmetadata.c	2017-06-26 13:29:36.000000000 +0200
+++ dovecot-2.2.31/src/imap/cmd-setmetadata.c	2026-04-09 20:19:07.289935838 +0200
@@ -272,7 +272,7 @@ 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);
 	o_stream_unset_flush_callback(client->output);
 
 	cmd->func = cmd_setmetadata_continue;
diff -rup dovecot-2.2.31-orig/src/imap/imap-client.c dovecot-2.2.31/src/imap/imap-client.c
--- dovecot-2.2.31-orig/src/imap/imap-client.c	2017-06-26 13:29:36.000000000 +0200
+++ dovecot-2.2.31/src/imap/imap-client.c	2026-04-09 20:19:14.545997054 +0200
@@ -850,7 +850,7 @@ 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);
 	}
 	return cmd;
 }
Nur in dovecot-2.2.31-orig/src/imap: imap-client.h.orig.
diff -rup dovecot-2.2.31-orig/src/imap-login/imap-login-client.c dovecot-2.2.31/src/imap-login/imap-login-client.c
--- dovecot-2.2.31-orig/src/imap-login/imap-login-client.c	2017-06-26 13:29:36.000000000 +0200
+++ dovecot-2.2.31/src/imap-login/imap-login-client.c	2026-04-09 20:25:18.925071140 +0200
@@ -334,7 +334,7 @@ static int cmd_id(struct imap_client *cl
 		client->cmd_id = id = i_new(struct imap_client_cmd_id, 1);
 		id->parser = imap_parser_create(client->common.input,
 						client->common.output,
-						MAX_IMAP_LINE);
+						MAX_IMAP_LINE, NULL);
 		parser_flags = IMAP_PARSE_FLAG_STOP_AT_LIST;
 	} else {
 		id = client->cmd_id;
@@ -602,10 +602,13 @@ 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, MAX_IMAP_LINE);
+				   imap_client->common.output, MAX_IMAP_LINE, &params);
 	client->io = io_add(client->fd, IO_READ, client_input, client);
 }
 
@@ -636,10 +639,13 @@ 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, MAX_IMAP_LINE);
+				   imap_client->common.output, MAX_IMAP_LINE, &params);
 
 	/* CRLF is lost from buffer when streams are reopened. */
 	imap_client->skip_line = FALSE;
diff -rup dovecot-2.2.31-orig/src/imap-login/imap-login-client.h dovecot-2.2.31/src/imap-login/imap-login-client.h
--- dovecot-2.2.31-orig/src/imap-login/imap-login-client.h	2017-06-26 13:29:36.000000000 +0200
+++ dovecot-2.2.31/src/imap-login/imap-login-client.h	2026-04-09 20:21:33.667170751 +0200
@@ -8,6 +8,10 @@
 /* Master prefix is: <1|0><imap tag><NUL> */
 #define IMAP_TAG_MAX_LEN (LOGIN_MAX_MASTER_PREFIX_LEN-2)
 
+/* 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,
diff -rup dovecot-2.2.31-orig/src/lib/strfuncs.c dovecot-2.2.31/src/lib/strfuncs.c
--- dovecot-2.2.31-orig/src/lib/strfuncs.c	2017-06-26 13:29:36.000000000 +0200
+++ dovecot-2.2.31/src/lib/strfuncs.c	2026-04-09 19:58:47.843645194 +0200
@@ -491,6 +491,21 @@ bool mem_equals_timing_safe(const void *
 	return ret == 0;
 }
 
+bool str_equals_timing_almost_safe(const char *s1, const char *s2)
+{
+        size_t i;
+        int ret = 0;
+
+        for (i = 0; s1[i] != '\0' && s2[i] != '\0'; i++)
+                ret |= s1[i] ^ s2[i];
+        ret |= s1[i] ^ s2[i];
+
+        /* make sure the compiler optimizer doesn't try to break out of the
+           above loop early. */
+        timing_safety_unoptimization = ret;
+        return ret == 0;
+}
+
 static char **
 split_str(pool_t pool, const char *data, const char *separators, int spaces)
 {
diff -rup dovecot-2.2.31-orig/src/lib/strfuncs.h dovecot-2.2.31/src/lib/strfuncs.h
--- dovecot-2.2.31-orig/src/lib/strfuncs.h	2017-06-26 13:29:36.000000000 +0200
+++ dovecot-2.2.31/src/lib/strfuncs.h	2026-04-09 19:59:42.340105107 +0200
@@ -69,6 +69,11 @@ int i_strcasecmp_p(const char *const *p1
 /* Returns TRUE if the two memory areas are equal. This function is safe
    against timing attacks, so it compares all the bytes every time. */
 bool mem_equals_timing_safe(const void *p1, const void *p2, size_t size);
+/* Returns TRUE if the two strings are equal. Similar to
+   mem_equals_timing_safe() this function is safe against timing attacks when
+   the string lengths are the same. If not, the length of the secret string may
+   be leaked, but otherwise the contents won't be. */
+bool str_equals_timing_almost_safe(const char *s1, const char *s2);
 
 static inline char *i_strchr_to_next(const char *str, char chr)
 {
Nur in dovecot-2.2.31-orig/src/lib-auth: auth-client-request.c.orig.
diff -rup dovecot-2.2.31-orig/src/lib-imap/imap-bodystructure.c dovecot-2.2.31/src/lib-imap/imap-bodystructure.c
--- dovecot-2.2.31-orig/src/lib-imap/imap-bodystructure.c	2017-06-26 13:29:36.000000000 +0200
+++ dovecot-2.2.31/src/lib-imap/imap-bodystructure.c	2026-04-09 20:19:43.338239957 +0200
@@ -645,7 +645,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_t)-1);
+	parser = imap_parser_create(input, NULL, (size_t)-1, NULL);
 	ret = imap_parser_finish_line(parser, 0,
 				      IMAP_PARSE_FLAG_LITERAL_TYPE, &args);
 	if (ret < 0) {
@@ -893,7 +893,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_t)-1);
+	parser = imap_parser_create(input, NULL, (size_t)-1, NULL);
 	ret = imap_parser_finish_line(parser, 0, IMAP_PARSE_FLAG_NO_UNESCAPE |
 				      IMAP_PARSE_FLAG_LITERAL_TYPE, &args);
 	if (ret < 0) {
diff -rup dovecot-2.2.31-orig/src/lib-imap/imap-envelope.c dovecot-2.2.31/src/lib-imap/imap-envelope.c
--- dovecot-2.2.31-orig/src/lib-imap/imap-envelope.c	2017-06-26 13:29:36.000000000 +0200
+++ dovecot-2.2.31/src/lib-imap/imap-envelope.c	2026-04-09 20:19:51.090305359 +0200
@@ -228,7 +228,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_t)-1);
+	parser = imap_parser_create(input, NULL, (size_t)-1, NULL);
 	ret = imap_parser_finish_line(parser, 0,
 				      IMAP_PARSE_FLAG_LITERAL_TYPE, &args);
 	if (ret < 0) {
diff -rup dovecot-2.2.31-orig/src/lib-imap/imap-id.c dovecot-2.2.31/src/lib-imap/imap-id.c
--- dovecot-2.2.31-orig/src/lib-imap/imap-id.c	2017-06-26 13:29:01.000000000 +0200
+++ dovecot-2.2.31/src/lib-imap/imap-id.c	2026-04-09 20:19:56.426350377 +0200
@@ -108,7 +108,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_t)-1);
+	parser = imap_parser_create(input, NULL, (size_t)-1, NULL);
 	if (imap_parser_finish_line(parser, 0, 0, &args) <= 0)
 		ret = "NIL";
 	else
diff -rup dovecot-2.2.31-orig/src/lib-imap/imap-parser.c dovecot-2.2.31/src/lib-imap/imap-parser.c
--- dovecot-2.2.31-orig/src/lib-imap/imap-parser.c	2026-04-09 18:24:18.072191673 +0200
+++ dovecot-2.2.31/src/lib-imap/imap-parser.c	2026-04-10 15:10:06.665624728 +0200
@@ -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 */
@@ -67,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)
 {
 	struct imap_parser *parser;
 
@@ -78,6 +81,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;
@@ -114,6 +121,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;
@@ -198,6 +206,11 @@ static int imap_parser_close_list(struct
 		parser->error = "Unexpected ')'";
 		return FALSE;
 	}
+	if (parser->list_count >= parser->list_count_limit) {
+		parser->error = "Too many '('";
+		return FALSE;
+	}
+	parser->list_count++;
 
 	arg = imap_arg_create(parser);
 	arg->type = IMAP_ARG_EOL;
diff -rup dovecot-2.2.31-orig/src/lib-imap/imap-parser.h dovecot-2.2.31/src/lib-imap/imap-parser.h
--- dovecot-2.2.31-orig/src/lib-imap/imap-parser.h	2017-06-26 13:29:36.000000000 +0200
+++ dovecot-2.2.31/src/lib-imap/imap-parser.h	2026-04-10 15:10:15.865700449 +0200
@@ -29,6 +29,15 @@ enum imap_parser_flags {
 	IMAP_PARSE_FLAG_STOP_AT_LIST	= 0x100
 };
 
+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;
 
 /* Create new IMAP argument parser. output is used for sending command
@@ -44,7 +53,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) ATTR_NULL(2);
 void imap_parser_ref(struct imap_parser *parser);
 void imap_parser_unref(struct imap_parser **parser);
 
diff -rup dovecot-2.2.31-orig/src/lib-imap/test-imap-parser.c dovecot-2.2.31/src/lib-imap/test-imap-parser.c
--- dovecot-2.2.31-orig/src/lib-imap/test-imap-parser.c	2017-06-26 13:29:36.000000000 +0200
+++ dovecot-2.2.31/src/lib-imap/test-imap-parser.c	2026-04-10 17:50:22.768854923 +0200
@@ -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++) {
diff -rup dovecot-2.2.31-orig/src/lib-imap-client/imapc-connection.c dovecot-2.2.31/src/lib-imap-client/imapc-connection.c
--- dovecot-2.2.31-orig/src/lib-imap-client/imapc-connection.c	2017-06-26 13:29:36.000000000 +0200
+++ dovecot-2.2.31/src/lib-imap-client/imapc-connection.c	2026-04-09 20:19:21.954059552 +0200
@@ -1762,7 +1762,7 @@ static void imapc_connection_connect_nex
 				    conn);
 	conn->io = io_add(fd, IO_WRITE, 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,
diff -rup dovecot-2.2.31-orig/src/lib-imap-storage/imap-msgpart.c dovecot-2.2.31/src/lib-imap-storage/imap-msgpart.c
--- dovecot-2.2.31-orig/src/lib-imap-storage/imap-msgpart.c	2017-06-26 13:29:36.000000000 +0200
+++ dovecot-2.2.31/src/lib-imap-storage/imap-msgpart.c	2026-04-09 20:19:33.018152892 +0200
@@ -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_t)-1);
+	parser = imap_parser_create(input, NULL, (size_t)-1, NULL);
 
 	if (imap_parser_finish_line(parser, 0, 0, &args) > 0 &&
 	    imap_arg_get_list_full(args, &hdr_list, &list_count) &&
Nur in dovecot-2.2.31-orig/src/lib-mail: message-part-data.c.orig.
diff -rup dovecot-2.2.31-orig/src/lib-mail/rfc2231-parser.c dovecot-2.2.31/src/lib-mail/rfc2231-parser.c
--- dovecot-2.2.31-orig/src/lib-mail/rfc2231-parser.c	2026-04-09 18:24:18.012191172 +0200
+++ dovecot-2.2.31/src/lib-mail/rfc2231-parser.c	2026-04-09 20:29:31.055198250 +0200
@@ -45,7 +45,7 @@ int rfc2231_parse(struct rfc822_parser_c
 	const struct rfc2231_parameter *rfc2231_params;
 	const char *key, *value, *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;
 	int ret;
 
@@ -56,6 +56,8 @@ int rfc2231_parse(struct rfc822_parser_c
 	t_array_init(&result, 8);
 	t_array_init(&rfc2231_params_arr, 8);
 	while ((ret = rfc822_parse_content_param(ctx, &key, &value)) != 0) {
+		if (++params_count > RFC2231_MAX_PARAMS)
+			break;
 		if (ret < 0) {
 			/* try to continue anyway.. */
 			broken = TRUE;
diff -rup dovecot-2.2.31-orig/src/lib-mail/rfc822-parser.h dovecot-2.2.31/src/lib-mail/rfc822-parser.h
--- dovecot-2.2.31-orig/src/lib-mail/rfc822-parser.h	2026-04-09 18:24:18.016191205 +0200
+++ dovecot-2.2.31/src/lib-mail/rfc822-parser.h	2026-04-09 20:30:31.667709614 +0200
@@ -12,6 +12,11 @@ struct rfc822_parser_context {
 	((rfc822_atext_chars[(int)(unsigned char)(c)] & 3) != 0)
 extern unsigned char rfc822_atext_chars[256];
 
+/* 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
+
 /* Parse given data using RFC 822 token parser. */
 void rfc822_parser_init(struct rfc822_parser_context *ctx,
 			const unsigned char *data, size_t size,
Nur in dovecot-2.2.31-orig/src/lib-master: master-service-settings.c.orig.
Nur in dovecot-2.2.31-orig/src/lib-master: master-service-settings.h.orig.
Nur in dovecot-2.2.31-orig/src/login-common: login-settings.c.orig.
diff -rup dovecot-2.2.31-orig/src/plugins/fts/Makefile.am dovecot-2.2.31/src/plugins/fts/Makefile.am
--- dovecot-2.2.31-orig/src/plugins/fts/Makefile.am	2017-06-26 13:29:36.000000000 +0200
+++ dovecot-2.2.31/src/plugins/fts/Makefile.am	2026-04-10 10:59:53.003755973 +0200
@@ -62,9 +62,6 @@ xml2text_SOURCES = xml2text.c
 xml2text_LDADD = fts-parser-html.lo $(LIBDOVECOT)
 xml2text_DEPENDENCIES = $(module_LTLIBRARIES) $(LIBDOVECOT_DEPS)
 
-pkglibexec_SCRIPTS = decode2text.sh
-EXTRA_DIST = $(pkglibexec_SCRIPTS)
-
 doveadm_module_LTLIBRARIES = \
 	lib20_doveadm_fts_plugin.la
 
diff -rup dovecot-2.2.31-orig/src/plugins/virtual/virtual-config.c dovecot-2.2.31/src/plugins/virtual/virtual-config.c
--- dovecot-2.2.31-orig/src/plugins/virtual/virtual-config.c	2017-06-26 13:29:36.000000000 +0200
+++ dovecot-2.2.31/src/plugins/virtual/virtual-config.c	2026-04-09 20:20:39.366712642 +0200
@@ -55,7 +55,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_t)-1);
+	imap_parser = imap_parser_create(input, NULL, (size_t)-1, NULL);
 	ret = imap_parser_finish_line(imap_parser, 0,  0, &args);
 	if (ret < 0) {
 		sargs = NULL;
