Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected]
Control: affects -1 + src:cyrus-imapd
User: [email protected]
Usertags: pu

[ Reason ]
9 open CVE issues in trixie that are fixed in testing.

[ Impact ]
Users are vulnerable to the security issues.

[ Tests ]
I (sponsor) have only build-tested this on amd64.
The submitter may have done additional tests and I have
asked him to submit additional details.

[ Risks ]
(Discussion of the risks involved. E.g. code is trivial or
complex, alternatives available.)

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in stable
  [x] the issue is verified as fixed in unstable

[ Changes ]
This includes the upstream patches from the stable 3.10 tree that
are marked to fix the CVEs and apply cleanly on the trixie version.
diff -Nru cyrus-imapd-3.10.2/debian/changelog 
cyrus-imapd-3.10.2/debian/changelog
--- cyrus-imapd-3.10.2/debian/changelog 2026-07-12 21:29:05.000000000 +0200
+++ cyrus-imapd-3.10.2/debian/changelog 2026-07-27 23:12:24.000000000 +0200
@@ -1,3 +1,11 @@
+cyrus-imapd (3.10.2-1+deb13u2) trixie; urgency=medium
+
+  * Add CVE fixes from upstream branch/version 3.10.3: CVE-2026-47084,
+    CVE-2026-47086, CVE-2026-47087, CVE-2026-47081, CVE-2026-47089,
+    CVE-2026-47085, CVE-2026-47083, CVE-2026-47088, CVE-2026-47082.
+
+ -- Codin <[email protected]>  Mon, 27 Jul 2026 14:12:24 -0700
+
 cyrus-imapd (3.10.2-1+deb13u1) trixie; urgency=medium
 
   * http_jmap: allow JMAP EventSource without WebSocket/wslay; backport
diff -Nru 
cyrus-imapd-3.10.2/debian/patches/0020-lmtp_sieve.c-enforce-ACL-on-vacation-fcc-destination.patch
 
cyrus-imapd-3.10.2/debian/patches/0020-lmtp_sieve.c-enforce-ACL-on-vacation-fcc-destination.patch
--- 
cyrus-imapd-3.10.2/debian/patches/0020-lmtp_sieve.c-enforce-ACL-on-vacation-fcc-destination.patch
   1970-01-01 01:00:00.000000000 +0100
+++ 
cyrus-imapd-3.10.2/debian/patches/0020-lmtp_sieve.c-enforce-ACL-on-vacation-fcc-destination.patch
   2026-07-27 23:12:24.000000000 +0200
@@ -0,0 +1,100 @@
+From db6d646d001c396dd1406db74eb4b98c081e15ed Mon Sep 17 00:00:00 2001
+From: Ricardo Signes <[email protected]>
+Date: Thu, 23 Apr 2026 08:31:14 +1000
+Subject: [PATCH] lmtp_sieve.c: enforce ACL on vacation :fcc destination
+
+Enforce *some* ACL check when delivering the fcc for a vacation message!
+Rather than pass aclcheck=0, pass ACL_INSERT: the script owner must be
+able to write to the target mailbox.
+
+This is CYR-2892, CVE-2026-47082.
+
+This problem was reported by Michael Lynch (mtlynch.io).
+
+Co-authored-by: Claude <[email protected]>
+---
+ .../Sieve/vacation_with_fcc_otheruser_denied  | 58 +++++++++++++++++++
+ imap/lmtp_sieve.c                             |  2 +-
+ 2 files changed, 59 insertions(+), 1 deletion(-)
+ create mode 100644 
cassandane/tiny-tests/Sieve/vacation_with_fcc_otheruser_denied
+
+diff --git a/cassandane/tiny-tests/Sieve/vacation_with_fcc_otheruser_denied 
b/cassandane/tiny-tests/Sieve/vacation_with_fcc_otheruser_denied
+new file mode 100644
+index 000000000..ed9ff9a92
+--- /dev/null
++++ b/cassandane/tiny-tests/Sieve/vacation_with_fcc_otheruser_denied
+@@ -0,0 +1,58 @@
++#!perl
++use Cassandane::Tiny;
++
++sub test_vacation_with_fcc_otheruser_denied
++    :min_version_3_1
++    :NoAltNameSpace
++    :want_smtpdaemon
++{
++    my ($self) = @_;
++
++    my $target = "user.other.target";
++
++    xlog $self, "Create victim user 'other' and a target folder";
++    $self->{instance}->create_user('other');
++
++    my $admintalk = $self->{adminstore}->get_client();
++    $admintalk->create($target)
++        or die "Cannot create $target: $@";
++
++    xlog $self, "Give cassandane read-only access (no 'i'/'p' rights)";
++    $admintalk->setacl($target, 'cassandane' => 'lrs');
++    $self->assert_str_equals('ok',
++        $admintalk->get_last_completion_response());
++
++    xlog $self, "Confirm cassandane cannot APPEND directly to $target";
++    my $talk = $self->{store}->get_client();
++    $talk->append($target,
++        "From: nobody\@example.com\r\n"
++        . "Subject: direct-append\r\n\r\n"
++        . "denied\r\n");
++    $self->assert_str_equals('no',
++        $talk->get_last_completion_response());
++
++    xlog $self, "Install a vacation rule that :fcc's into the victim's 
folder";
++    $self->{instance}->install_sieve_script(<<EOF
++require ["vacation", "fcc"];
++
++vacation :fcc "$target" :days 1 :addresses ["cassandane\@example.com"] text:
++I am out of the office today. I will answer your email as soon as I can.
++.
++;
++EOF
++    );
++
++    xlog $self, "Deliver a message to trigger the vacation auto-reply";
++    my $msg1 = $self->{gen}->generate(
++        subject => "Message 1",
++        to => Cassandane::Address->new(localpart => 'cassandane',
++                                       domain => 'example.com'),
++    );
++    $self->{instance}->deliver($msg1);
++
++    xlog $self, "Check that nothing was filed into the victim's folder";
++    $admintalk->select($target);
++    $self->assert_str_equals('ok',
++        $admintalk->get_last_completion_response());
++    $self->assert_num_equals(0, $admintalk->get_response_code('exists'));
++}
+diff --git a/imap/lmtp_sieve.c b/imap/lmtp_sieve.c
+index f13a26629..b85bf1ad2 100644
+--- a/imap/lmtp_sieve.c
++++ b/imap/lmtp_sieve.c
+@@ -1931,7 +1931,7 @@ static void do_fcc(script_data_t *sdata, 
sieve_fileinto_context_t *fcc,
+     }
+     if (!r) {
+         r = append_setup(&as, intname, userid, sdata->authstate,
+-                         0, NULL, NULL, 0, EVENT_MESSAGE_APPEND);
++                         ACL_INSERT, NULL, NULL, 0, EVENT_MESSAGE_APPEND);
+     }
+     if (!r) {
+         struct stagemsg *stage;
+-- 
+2.47.3
+
diff -Nru 
cyrus-imapd-3.10.2/debian/patches/0021-imap-message.c-fix-heap-exposure-in-nested-MIME-comm.patch
 
cyrus-imapd-3.10.2/debian/patches/0021-imap-message.c-fix-heap-exposure-in-nested-MIME-comm.patch
--- 
cyrus-imapd-3.10.2/debian/patches/0021-imap-message.c-fix-heap-exposure-in-nested-MIME-comm.patch
   1970-01-01 01:00:00.000000000 +0100
+++ 
cyrus-imapd-3.10.2/debian/patches/0021-imap-message.c-fix-heap-exposure-in-nested-MIME-comm.patch
   2026-07-27 23:12:24.000000000 +0200
@@ -0,0 +1,147 @@
+From 23495997b52a1ffdbc8b655d803f0b58167e40d6 Mon Sep 17 00:00:00 2001
+From: Ricardo Signes <[email protected]>
+Date: Wed, 22 Apr 2026 15:55:30 +1000
+Subject: [PATCH] imap/message.c: fix heap exposure in nested MIME comment
+ parsing
+
+Fix out-of-bounds read in message_parse_rfc822space() when parsing RFC
+822 comments that end with backslash. The backslash case would increment
+p past a NUL terminator, and the subsequent loop increment would read
+into adjacent heap memory.
+
+Add bounds check after backslash handling to prevent reading past the
+end of the buffer.
+
+This is CYR-2882, CVE-2026-47088.
+
+This problem was reported by Michael Lynch (mtlynch.io).
+
+Co-Authored-By: Claude <[email protected]>
+---
+ cassandane/Cassandane/Cyrus/MIME.pm           | 40 +++++++++++++++
+ cassandane/tiny-tests/MIME/nested_comment_oob | 50 +++++++++++++++++++
+ imap/message.c                                |  4 ++
+ 3 files changed, 94 insertions(+)
+ create mode 100644 cassandane/Cassandane/Cyrus/MIME.pm
+ create mode 100644 cassandane/tiny-tests/MIME/nested_comment_oob
+
+diff --git a/cassandane/Cassandane/Cyrus/MIME.pm 
b/cassandane/Cassandane/Cyrus/MIME.pm
+new file mode 100644
+index 000000000..58df5a251
+--- /dev/null
++++ b/cassandane/Cassandane/Cyrus/MIME.pm
+@@ -0,0 +1,40 @@
++# SPDX-License-Identifier: BSD-3-Clause-CMU
++# See COPYING file at the root of the distribution for more details.
++
++package Cassandane::Cyrus::MIME;
++use strict;
++use warnings;
++use Data::Dumper;
++
++use base qw(Cassandane::Cyrus::TestCase);
++use Cassandane::Util::Log;
++
++sub new
++{
++    my ($class, @args) = @_;
++
++    my $config = Cassandane::Config->default()->clone();
++
++    my $self = $class->SUPER::new({
++        config => $config,
++        services => [ 'imap' ]
++    }, @args);
++
++    return $self;
++}
++
++sub set_up
++{
++    my ($self) = @_;
++    $self->SUPER::set_up();
++}
++
++sub tear_down
++{
++    my ($self) = @_;
++    $self->SUPER::tear_down();
++}
++
++use Cassandane::Tiny::Loader 'tiny-tests/MIME';
++
++1;
+diff --git a/cassandane/tiny-tests/MIME/nested_comment_oob 
b/cassandane/tiny-tests/MIME/nested_comment_oob
+new file mode 100644
+index 000000000..b47f6b1b3
+--- /dev/null
++++ b/cassandane/tiny-tests/MIME/nested_comment_oob
+@@ -0,0 +1,50 @@
++#!perl
++use Cassandane::Tiny;
++
++sub test_nested_comment_oob
++{
++    my ($self) = @_;
++
++    my $talk = $self->{store}->get_client();
++
++    # Create a multipart message where the vulnerability is in a nested part.
++    # Based on the PoC description, this reproduces the backslash handling bug
++    # in message_parse_rfc822space() when parsing nested Content-Type headers.
++    # The malformed header must be the last content to ensure backslash is 
final byte.
++    my $msg = <<'EOF';
++From: [email protected]
++To: [email protected]
++Subject: Test heap disclosure
++Content-Type: multipart/mixed; boundary="BOUNDARY"
++
++--BOUNDARY
++Content-Type: text/plain
++
++This is a normal part.
++
++--BOUNDARY
++Content-Type: text/plain (\
++EOF
++
++    # Remove trailing newline so backslash is the final byte before NUL
++    chomp $msg;
++    $msg =~ s/\r?\n/\r\n/gs;
++
++    # Append the message
++    $talk->append('INBOX', $msg) || die $@;
++
++    # Select the mailbox
++    $talk->select('INBOX');
++    $self->assert_str_equals('ok', $talk->get_last_completion_response());
++
++    # Fetch BODYSTRUCTURE - this exercises the vulnerable MIME parsing code
++    # In vulnerable versions, this may crash or leak heap data as MIME 
parameters
++    my $response = $talk->fetch('1', 'BODYSTRUCTURE');
++    $self->assert_str_equals('ok', $talk->get_last_completion_response());
++
++    # Log the bodystructure for manual inspection of any anomalies
++    # In a release build with heap spray, unexpected parameters may appear
++    if ($response && $response->{1} && $response->{1}->{bodystructure}) {
++        xlog $self, "BODYSTRUCTURE: " . 
Data::Dumper::Dumper($response->{1}->{bodystructure});
++    }
++}
+diff --git a/imap/message.c b/imap/message.c
+index a5b633e19..f18b1c6f6 100644
+--- a/imap/message.c
++++ b/imap/message.c
+@@ -1768,6 +1768,10 @@ static void message_parse_rfc822space(const char **s)
+ 
+                 case '\\':
+                     p++;
++                    if (*p == '\0') {
++                        *s = 0;     /* backslash at end of string */
++                        return;
++                    }
+                     break;
+ 
+                 case '(':
+-- 
+2.47.3
+
diff -Nru 
cyrus-imapd-3.10.2/debian/patches/0022-imapd-MULTISEARCH-must-check-ACL_READ-on-each-mailbo.patch
 
cyrus-imapd-3.10.2/debian/patches/0022-imapd-MULTISEARCH-must-check-ACL_READ-on-each-mailbo.patch
--- 
cyrus-imapd-3.10.2/debian/patches/0022-imapd-MULTISEARCH-must-check-ACL_READ-on-each-mailbo.patch
   1970-01-01 01:00:00.000000000 +0100
+++ 
cyrus-imapd-3.10.2/debian/patches/0022-imapd-MULTISEARCH-must-check-ACL_READ-on-each-mailbo.patch
   2026-07-27 23:12:24.000000000 +0200
@@ -0,0 +1,94 @@
+From 0534c4e30a4a09e9b8d606bf8f0e874152e8f294 Mon Sep 17 00:00:00 2001
+From: Ricardo Signes <[email protected]>
+Date: Wed, 22 Apr 2026 08:51:29 +1000
+Subject: [PATCH] imapd: MULTISEARCH must check ACL_READ on each mailbox
+
+multisearch_cb opened caller-supplied mailboxes from
+MAILBOXES/SUBTREE/SUBTREE-ONE and ran index_search on them without
+checking whether the caller could read the mailbox. SELECT has the
+equivalent gate (imapd.c:5001); MULTISEARCH did not.
+
+The effect is a cross-user read oracle: SUBTREE on another user's
+account returns one `* ESEARCH ... MAILBOX "..."` line per folder
+(folder enumeration for free), and BODY/SUBJECT predicates then probe
+the contents one search at a time. An attacker only needs to be able
+to name a target mailbox.
+
+This is CYR-2881, CVE-2026-47083.
+
+This problem was reported by Michael Lynch (mtlynch.io).
+
+Co-Authored-By: Claude <[email protected]>
+---
+ cassandane/Cassandane/Cyrus/Search.pm | 40 +++++++++++++++++++++++++++
+ imap/imapd.c                          |  5 ++++
+ 2 files changed, 45 insertions(+)
+
+diff --git a/cassandane/Cassandane/Cyrus/Search.pm 
b/cassandane/Cassandane/Cyrus/Search.pm
+index 19e16fab7..d9e5e9e1e 100644
+--- a/cassandane/Cassandane/Cyrus/Search.pm
++++ b/cassandane/Cassandane/Cyrus/Search.pm
+@@ -757,4 +757,44 @@ sub test_uidsearch_empty
+     $self->assert_str_equals('0', $results[0][3]);
+ }
+ 
++sub test_multisearch_cross_user
++    :NoAltNamespace
++{
++    my ($self) = @_;
++
++    my $admintalk = $self->{adminstore}->get_client;
++    my $talk = $self->{store}->get_client;
++
++    # victim has a private subfolder with a message. cassandane has no
++    # explicit grant on it, only whatever the "anyone p" default provides --
++    # i.e. ACL_POST, which is not enough to run a search.
++    $self->{instance}->create_user('victim');
++
++    $admintalk->create('user.victim.private')
++        || die "create: " . $admintalk->get_last_error;
++
++    $admintalk->append(
++        'user.victim.private',
++        "From: t\@example.com\r\nSubject: secret\r\n\r\nconfidential body",
++    ) || die "append: " . $admintalk->get_last_error;
++
++    # Check our assumptions: default user has no access to victim's private
++    # folder.
++    $talk->select('user.victim.private');
++    $self->assert_str_equals('no', $talk->get_last_completion_response);
++
++    # The actual test: assert that cassandane user can't find anything by
++    # ESEARCHing victim's private mailbox.
++    my @esearch_responses;
++    $talk->_imap_cmd(
++        'ESEARCH', 0,
++        { esearch => sub { push @esearch_responses, $_[1] } },
++        'IN', '(MAILBOXES "user.victim.private")',
++        'RETURN', '(ALL)', 'ALL',
++    );
++
++    $self->assert_str_equals('ok', $talk->get_last_completion_response);
++    $self->assert_deep_equals([], \@esearch_responses);
++}
++
+ 1;
+diff --git a/imap/imapd.c b/imap/imapd.c
+index f48b63911..89963ebe9 100644
+--- a/imap/imapd.c
++++ b/imap/imapd.c
+@@ -6080,6 +6080,11 @@ static int multisearch_cb(const mbentry_t *mbentry, 
void *rock)
+         hash_lookup(mbentry->name, &mrock->mailboxes))
+         return 0;
+ 
++    /* Skip mailboxes the caller can't read. */
++    if (!imapd_userisadmin &&
++        !(cyrus_acl_myrights(imapd_authstate, mbentry->acl) & ACL_READ))
++        return 0;
++
+     switch (mrock->filter) {
+     case SEARCH_SOURCE_INBOXES:
+         /* Only allow user's INBOX or those postable by anonymous */
+-- 
+2.47.3
+
diff -Nru 
cyrus-imapd-3.10.2/debian/patches/0023-imapd-reject-URLFETCH-when-no-mboxkey-exists-for-the.patch
 
cyrus-imapd-3.10.2/debian/patches/0023-imapd-reject-URLFETCH-when-no-mboxkey-exists-for-the.patch
--- 
cyrus-imapd-3.10.2/debian/patches/0023-imapd-reject-URLFETCH-when-no-mboxkey-exists-for-the.patch
   1970-01-01 01:00:00.000000000 +0100
+++ 
cyrus-imapd-3.10.2/debian/patches/0023-imapd-reject-URLFETCH-when-no-mboxkey-exists-for-the.patch
   2026-07-27 23:12:24.000000000 +0200
@@ -0,0 +1,44 @@
+From 1d39d32c3b6a61241651763855b336122686fd7e Mon Sep 17 00:00:00 2001
+From: Ricardo Signes <[email protected]>
+Date: Tue, 21 Apr 2026 08:16:10 +1000
+Subject: [PATCH] imapd: reject URLFETCH when no mboxkey exists for the mailbox
+
+Instead of treating "there's no mboxkey.db entry for this folder" as
+indicating a zero-length key, treat a missing mboxkey entry as a
+validation failure.
+
+(Also close the mboxkey db on the previously-unclosed error paths.)
+
+This is CYR-2876, CVE-2026-47085.
+
+This problem reported by Matthew Horsfall.
+
+Co-Authored-By: Claude <[email protected]>
+---
+ imap/imapd.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/imap/imapd.c b/imap/imapd.c
+index 460c6aac6..f48b63911 100644
+--- a/imap/imapd.c
++++ b/imap/imapd.c
+@@ -14076,7 +14076,15 @@ static void cmd_urlfetch(char *tag)
+                 if (r) break;
+ 
+                 r = mboxkey_read(mboxkey_db, intname, &key, &keylen);
+-                if (r) break;
++                if (!r && (!key || !keylen)) {
++                    /* If there's no key, we can't possibly validate against
++                     * it! */
++                    r = IMAP_BADURL;
++                }
++                if (r) {
++                    mboxkey_close(mboxkey_db);
++                    break;
++                }
+ 
+                 HMAC(EVP_sha1(), key, keylen, (unsigned char *) arg.s,
+                      url.urlauth.rump_len, vtoken, &vtoken_len);
+-- 
+2.47.3
+
diff -Nru 
cyrus-imapd-3.10.2/debian/patches/0024-imapd-LISTRIGHTS-requires-admin-rights.patch
 
cyrus-imapd-3.10.2/debian/patches/0024-imapd-LISTRIGHTS-requires-admin-rights.patch
--- 
cyrus-imapd-3.10.2/debian/patches/0024-imapd-LISTRIGHTS-requires-admin-rights.patch
 1970-01-01 01:00:00.000000000 +0100
+++ 
cyrus-imapd-3.10.2/debian/patches/0024-imapd-LISTRIGHTS-requires-admin-rights.patch
 2026-07-27 23:12:24.000000000 +0200
@@ -0,0 +1,43 @@
+From 5c97794e5270b472130af4531f290812cbcc6879 Mon Sep 17 00:00:00 2001
+From: Ricardo Signes <[email protected]>
+Date: Tue, 21 Apr 2026 08:28:15 +1000
+Subject: [PATCH] imapd: LISTRIGHTS requires admin rights
+
+cmd_listrights was refusing only when the caller had *no* rights at
+all on the target mailbox, when it should've been requiring admin
+rights.
+
+With this patch, we'll properly require ACL_ADMIN (owners and admins
+still pass through), matching the check cmd_getacl already uses.  When
+the caller has ACL_LOOKUP but not ACL_ADMIN, return PERMISSION_DENIED;
+otherwise hide the mailbox as NONEXISTENT.
+
+This is CYR-2872, CVE-2026-47089.
+
+This problem reported by Matthew Horsfall.
+
+Co-Authored-By: Claude <[email protected]>
+---
+ imap/imapd.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/imap/imapd.c b/imap/imapd.c
+index eacd6cedd..460c6aac6 100644
+--- a/imap/imapd.c
++++ b/imap/imapd.c
+@@ -8530,9 +8530,10 @@ static void cmd_listrights(char *tag, char *name, char 
*identifier)
+     if (!r) {
+         rights = cyrus_acl_myrights(imapd_authstate, mbentry->acl);
+ 
+-        if (!rights && !imapd_userisadmin &&
++        if (!(rights & ACL_ADMIN) && !imapd_userisadmin &&
+             !mboxname_userownsmailbox(imapd_userid, intname)) {
+-            r = IMAP_MAILBOX_NONEXISTENT;
++            r = (rights & ACL_LOOKUP) ?
++                IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
+         }
+     }
+ 
+-- 
+2.47.3
+
diff -Nru 
cyrus-imapd-3.10.2/debian/patches/0025-imapd-require-read-access-for-XAPPLEPUSHSERVICE-mail.patch
 
cyrus-imapd-3.10.2/debian/patches/0025-imapd-require-read-access-for-XAPPLEPUSHSERVICE-mail.patch
--- 
cyrus-imapd-3.10.2/debian/patches/0025-imapd-require-read-access-for-XAPPLEPUSHSERVICE-mail.patch
   1970-01-01 01:00:00.000000000 +0100
+++ 
cyrus-imapd-3.10.2/debian/patches/0025-imapd-require-read-access-for-XAPPLEPUSHSERVICE-mail.patch
   2026-07-27 23:12:24.000000000 +0200
@@ -0,0 +1,37 @@
+From 50f77bad3048e7050ad0cd448615d9643463c16d Mon Sep 17 00:00:00 2001
+From: Ricardo Signes <[email protected]>
+Date: Tue, 21 Apr 2026 09:05:40 +1000
+Subject: [PATCH] imapd: require read access for XAPPLEPUSHSERVICE mailboxes
+
+Only accept a mailbox if the caller is its owner, an admin, or holds
+ACL_READ. Anything else is silently skipped (no echo, no event), which
+also preserves the existing "missing" behaviour for non-existent names.
+
+This is CYR-2871, CVE-2026-47081.
+
+This problem reported by Matthew Horsfall.
+
+Co-Authored-By: Claude <[email protected]>
+---
+ imap/imapd.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/imap/imapd.c b/imap/imapd.c
+index fba38ed2c..eacd6cedd 100644
+--- a/imap/imapd.c
++++ b/imap/imapd.c
+@@ -14820,7 +14820,10 @@ static void cmd_xapplepushservice(const char *tag,
+         char *intname =
+             mboxname_from_external(name, &imapd_namespace, imapd_userid);
+         r = mlookup(tag, name, intname, &mbentry);
+-        if (!r && mbtype_isa(mbentry->mbtype) == MBTYPE_EMAIL) {
++        if (!r && mbtype_isa(mbentry->mbtype) == MBTYPE_EMAIL &&
++            (imapd_userisadmin ||
++             mboxname_userownsmailbox(imapd_userid, intname) ||
++             (cyrus_acl_myrights(imapd_authstate, mbentry->acl) & ACL_READ))) 
{
+             strarray_push(&notif_mailboxes, name);
+             if (applepushserviceargs->aps_version >= 2) {
+                 prot_puts(imapd_out, "* XAPPLEPUSHSERVICE \"mailbox\" ");
+-- 
+2.47.3
+
diff -Nru 
cyrus-imapd-3.10.2/debian/patches/0026-imapd.c-re-check-URLAUTH-authorizer-access-just-in-t.patch
 
cyrus-imapd-3.10.2/debian/patches/0026-imapd.c-re-check-URLAUTH-authorizer-access-just-in-t.patch
--- 
cyrus-imapd-3.10.2/debian/patches/0026-imapd.c-re-check-URLAUTH-authorizer-access-just-in-t.patch
   1970-01-01 01:00:00.000000000 +0100
+++ 
cyrus-imapd-3.10.2/debian/patches/0026-imapd.c-re-check-URLAUTH-authorizer-access-just-in-t.patch
   2026-07-27 23:12:24.000000000 +0200
@@ -0,0 +1,52 @@
+From 8380d0fb3d74b5c3a0a198db24ba4d8835781587 Mon Sep 17 00:00:00 2001
+From: Ricardo Signes <[email protected]>
+Date: Wed, 29 Apr 2026 08:38:25 +1000
+Subject: [PATCH] imapd.c: re-check URLAUTH authorizer access just in time
+
+cmd_urlfetch validated the HMAC token against the authorizer's mboxkey,
+but skipped any ACL check whenever url.urlauth.access was set.  Sure,
+the rights existed right at that moment, but if access is revoked after
+the URL is created, the URL needs to stop working.  We need to just
+check access JIT.
+
+This is CYR-2868, CVE-2026-47087.
+
+Co-Authored-By: Claude <[email protected]>
+---
+ imap/imapd.c | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+diff --git a/imap/imapd.c b/imap/imapd.c
+index 3392dc622..fba38ed2c 100644
+--- a/imap/imapd.c
++++ b/imap/imapd.c
+@@ -14113,6 +14113,26 @@ static void cmd_urlfetch(char *tag)
+         }
+         if (r) goto err;
+ 
++        /* For URLAUTH-protected URLs, re-check the authorizer's ACL.  The
++         * HMAC asserts that authorization DID exist, but may have since been
++         * revoked.  We can't read the ACL via state->mailbox here: when the
++         * URL targets the currently-selected mailbox we reuse imapd_index,
++         * whose mailbox handle is closed between commands. */
++        if (url.urlauth.access) {
++            mbentry_t *authz_mbentry = NULL;
++            r = mlookup(NULL, NULL, intname, &authz_mbentry);
++            if (!r) {
++                struct auth_state *authzstate = auth_newstate(url.user);
++                int authz_rights =
++                    cyrus_acl_myrights(authzstate, authz_mbentry->acl);
++                auth_freestate(authzstate);
++                if (!(authz_rights & ACL_READ))
++                    r = IMAP_BADURL;
++            }
++            mboxlist_entry_free(&authz_mbentry);
++            if (r) goto err;
++        }
++
+         if (url.uidvalidity &&
+            (state->mailbox->i.uidvalidity != url.uidvalidity)) {
+             r = IMAP_BADURL;
+-- 
+2.47.3
+
diff -Nru 
cyrus-imapd-3.10.2/debian/patches/0027-imapd-require-read-access-on-mailbox-in-GENURLAUTH.patch
 
cyrus-imapd-3.10.2/debian/patches/0027-imapd-require-read-access-on-mailbox-in-GENURLAUTH.patch
--- 
cyrus-imapd-3.10.2/debian/patches/0027-imapd-require-read-access-on-mailbox-in-GENURLAUTH.patch
     1970-01-01 01:00:00.000000000 +0100
+++ 
cyrus-imapd-3.10.2/debian/patches/0027-imapd-require-read-access-on-mailbox-in-GENURLAUTH.patch
     2026-07-27 23:12:24.000000000 +0200
@@ -0,0 +1,45 @@
+From e7a28ccf9bddd64db45542ea4a109d8060eb6f6d Mon Sep 17 00:00:00 2001
+From: Ricardo Signes <[email protected]>
+Date: Tue, 21 Apr 2026 07:57:26 +1000
+Subject: [PATCH] imapd: require read access on mailbox in GENURLAUTH
+
+You can't grant access to things you can't access!  Without this check,
+any authenticated user could mint a URLAUTH token for any mailbox they
+could name, because cmd_urlfetch skipped the ACL check whenever
+urlauth.access is set -- it trusts that the presence of a valid HMAC
+means the authorizing user was entitled to delegate.
+
+Require the authorizer to have at least ACL_READ on the mailbox before
+issuing a token.
+
+This is CYR-2868, CVE-2026-47086.
+
+This problem reported by Matthew Horsfall.
+
+Co-Authored-By: Claude <[email protected]>
+---
+ imap/imapd.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/imap/imapd.c b/imap/imapd.c
+index dfe782f8f..3392dc622 100644
+--- a/imap/imapd.c
++++ b/imap/imapd.c
+@@ -14250,6 +14250,14 @@ static void cmd_genurlauth(char *tag)
+             continue;
+         }
+ 
++        /* You can't give permission you don't have! */
++        if (!imapd_userisadmin &&
++            !(cyrus_acl_myrights(imapd_authstate, mbentry->acl) & ACL_READ)) {
++            mboxlist_entry_free(&mbentry);
++            r = IMAP_BADURL;
++            goto err;
++        }
++
+         mboxlist_entry_free(&mbentry);
+ 
+         /* lookup key */
+-- 
+2.47.3
+
diff -Nru 
cyrus-imapd-3.10.2/debian/patches/0028-imapd-fix-cmd_delete-force-handling.patch
 
cyrus-imapd-3.10.2/debian/patches/0028-imapd-fix-cmd_delete-force-handling.patch
--- 
cyrus-imapd-3.10.2/debian/patches/0028-imapd-fix-cmd_delete-force-handling.patch
    1970-01-01 01:00:00.000000000 +0100
+++ 
cyrus-imapd-3.10.2/debian/patches/0028-imapd-fix-cmd_delete-force-handling.patch
    2026-07-27 23:12:24.000000000 +0200
@@ -0,0 +1,54 @@
+From 304255f5be82cbe9c0b7db7f4dba6b16381da2ec Mon Sep 17 00:00:00 2001
+From: ellie timoney <[email protected]>
+Date: Fri, 17 Apr 2026 11:55:05 +1000
+Subject: [PATCH] imapd: fix cmd_delete 'force' handling
+
+mboxlist_deletemailbox expects to be told whether this is a forced
+action by the MBOXLIST_DELETE_FORCE flag, but this was not being
+plumbed through.  Forced actions are supposed to require isadmin
+permission, but with the flag not set correctly, that check was
+being skipped.
+
+As a side effect, a non-admin user could invoke the admin-only
+"localdelete" command and delete mailboxes they shouldn't have
+rights to.
+
+This is CYR-2867, CVE-2026-47084.
+
+This problem was reported by Michael Lynch (mtlynch.io).
+---
+ imap/imapd.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/imap/imapd.c b/imap/imapd.c
+index 65ce5c053..dfe782f8f 100644
+--- a/imap/imapd.c
++++ b/imap/imapd.c
+@@ -7350,19 +7350,22 @@ static void cmd_delete(char *tag, char *name, int 
localonly, int force)
+     /* local mailbox */
+     if (!r) {
+         int isadmin = imapd_userisadmin || imapd_userisproxyadmin;
++        int delflags = force ? MBOXLIST_DELETE_FORCE : 0;
+ 
+         if (mbname_isdeleted(mbname)) {
+             r = mboxlist_deletemailbox(mbname_intname(mbname),
+                                        isadmin, imapd_userid,
+                                        imapd_authstate, mboxevent,
+-                                       MBOXLIST_DELETE_LOCALONLY);
++                                       delflags | MBOXLIST_DELETE_LOCALONLY);
+         }
+         else if (!isadmin && mbname_issystem(mbname)) {
+             r = IMAP_PERMISSION_DENIED;
+         }
+         else {
+             delete_user = mboxname_isusermailbox(mbname_intname(mbname), 1);
+-            int delflags = (1-force) ? MBOXLIST_DELETE_CHECKACL : 0;
++
++            if (!force)
++                delflags |= MBOXLIST_DELETE_CHECKACL;
+ 
+             if (!delete_user && mboxlist_haschildren(mbname_intname(mbname))) 
{
+                 r = IMAP_MAILBOX_HASCHILDREN;
+-- 
+2.47.3
+
diff -Nru cyrus-imapd-3.10.2/debian/patches/series 
cyrus-imapd-3.10.2/debian/patches/series
--- cyrus-imapd-3.10.2/debian/patches/series    2026-07-12 21:29:05.000000000 
+0200
+++ cyrus-imapd-3.10.2/debian/patches/series    2026-07-27 23:12:24.000000000 
+0200
@@ -7,4 +7,13 @@
 0012-Use-UnicodeData.txt-from-system.patch
 0018-increase-test-timeout.patch
 #0019-propagate-XXFLAGS.patch
+0020-lmtp_sieve.c-enforce-ACL-on-vacation-fcc-destination.patch
+0021-imap-message.c-fix-heap-exposure-in-nested-MIME-comm.patch
+0022-imapd-MULTISEARCH-must-check-ACL_READ-on-each-mailbo.patch
+0023-imapd-reject-URLFETCH-when-no-mboxkey-exists-for-the.patch
+0025-imapd-require-read-access-for-XAPPLEPUSHSERVICE-mail.patch
+0026-imapd.c-re-check-URLAUTH-authorizer-access-just-in-t.patch
+0027-imapd-require-read-access-on-mailbox-in-GENURLAUTH.patch
+0028-imapd-fix-cmd_delete-force-handling.patch
+0024-imapd-LISTRIGHTS-requires-admin-rights.patch
 eventsource-without-websocket.patch

Reply via email to