This is a patch generated by unpacking
https://bazaar.launchpad.net/tarball/1885
https://bazaar.launchpad.net/tarball/1893
as .tgz tarballs into separate directories and diffing it
with GNU diff -NEur:

diff -NEur bin/cleanarch bin/cleanarch
--- bin/cleanarch	2018-06-18 01:47:34.744000000 +0200
+++ bin/cleanarch	2022-01-11 04:08:45.300000000 +0100
@@ -60,7 +60,7 @@
 # From RFC 2822, a header field name must contain only characters from 33-126
 # inclusive, excluding colon.  I.e. from oct 41 to oct 176 less oct 072.  Must
 # use re.match() so that it's anchored at the beginning of the line.
-fre = re.compile(r'[\041-\071\073-\176]+')
+fre = re.compile(r'[\041-\071\073-\176]+:')
 
 
 
diff -NEur Mailman/Cgi/options.py Mailman/Cgi/options.py
--- Mailman/Cgi/options.py	2021-11-24 04:38:19.869000000 +0100
+++ Mailman/Cgi/options.py	2023-05-22 21:58:09.582000000 +0200
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2018 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2023 by the Free Software Foundation, Inc.
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
@@ -164,13 +164,40 @@
         loginpage(mlist, doc, None, language)
         print doc.Format()
         return
-    # Sanity check the user, but only give the "no such member" error when
-    # using public rosters, otherwise, we'll leak membership information.
+    # Sanity check the user, but we have to give the appropriate error msg
+    # to not potentially leak membership info. This is a kludge here. We
+    # have to check membership here to avoid LP: #1951769, but then we have
+    # to give the appropriate error to avoid LP: #1968443
+    msgc = _('If you are a list member, a confirmation email has been sent.')
+    msgb = _('You already have a subscription pending confirmation')
+    msga = _("""If you are a list member, your unsubscription request has been
+             forwarded to the list administrator for approval.""")
+    msgd = _("""If you are a list member,
+            your password has been emailed to you.""")
     if not mlist.isMember(user):
         if mlist.private_roster == 0:
             doc.addError(_('No such member: %(safeuser)s.'))
-            loginpage(mlist, doc, None, language)
-            print doc.Format()
+            user = None
+        elif cgidata.has_key('login-unsub'):
+            syslog('mischief',
+                   'Unsub attempt of non-member w/ private rosters: %s',
+                   user)
+            if mlist.unsubscribe_policy:
+                doc.addError(msga, tag='')
+            else:
+                doc.addError(msgc, tag='')
+            user = None
+        elif cgidata.has_key('login-remind'):
+            syslog('mischief',
+                   'Reminder attempt of non-member w/ private rosters: %s',
+                   user)
+            doc.addError(msgd, tag='')
+            user = None
+        # We get here with a non-None user in the case of a non-member with
+        # private rosters.  This creates a possible membership leak, but we
+        # fix that a different way. See LP: #2017813.
+        loginpage(mlist, doc, user, language)
+        print doc.Format()
         return
 
     # Avoid cross-site scripting attacks
@@ -204,10 +231,6 @@
     i18n.set_language(userlang)
 
     # Are we processing an unsubscription request from the login screen?
-    msgc = _('If you are a list member, a confirmation email has been sent.')
-    msgb = _('You already have a subscription pending confirmation')
-    msga = _("""If you are a list member, your unsubscription request has been
-             forwarded to the list administrator for approval.""")
     if cgidata.has_key('login-unsub'):
         # Because they can't supply a password for unsubscribing, we'll need
         # to do the confirmation dance.
@@ -233,39 +256,20 @@
             finally:
                 mlist.Unlock()
         else:
-            # Not a member
-            if mlist.private_roster == 0:
-                # Public rosters
-                doc.addError(_('No such member: %(safeuser)s.'))
-            else:
-                syslog('mischief',
-                       'Unsub attempt of non-member w/ private rosters: %s',
-                       user)
-                if mlist.unsubscribe_policy:
-                    doc.addError(msga, tag='')
-                else:
-                    doc.addError(msgc, tag='')
+            # Not a member handled above.
+            pass
         loginpage(mlist, doc, user, language)
         print doc.Format()
         return
 
     # Are we processing a password reminder from the login screen?
-    msg = _("""If you are a list member,
-            your password has been emailed to you.""")
     if cgidata.has_key('login-remind'):
         if mlist.isMember(user):
             mlist.MailUserPassword(user)
-            doc.addError(msg, tag='')
+            doc.addError(msgd, tag='')
         else:
-            # Not a member
-            if mlist.private_roster == 0:
-                # Public rosters
-                doc.addError(_('No such member: %(safeuser)s.'))
-            else:
-                syslog('mischief',
-                       'Reminder attempt of non-member w/ private rosters: %s',
-                       user)
-                doc.addError(msg, tag='')
+            # Not a member handled above.
+            pass
         loginpage(mlist, doc, user, language)
         print doc.Format()
         return
@@ -293,7 +297,9 @@
         # to authenticate via cgi (instead of cookie), then print an error
         # message.
         if cgidata.has_key('password'):
-            doc.addError(_('Authentication failed.'))
+            if mlist.private_roster == 0:
+                # Only add error with public rosters lp: #2015416
+                doc.addError(_('Authentication failed.'))
             remote = os.environ.get('HTTP_FORWARDED_FOR',
                      os.environ.get('HTTP_X_FORWARDED_FOR',
                      os.environ.get('REMOTE_ADDR',
@@ -307,9 +313,11 @@
                 syslog('mischief',
                        'Login failure with private rosters: %s from %s',
                        user, remote)
-                user = None
+                # Don't clear user here. See LP: #2017813.
             # give an HTTP 401 for authentication failure
-            print 'Status: 401 Unauthorized'
+            if mlist.private_roster == 0:
+                # Only add error with public rosters lp: #2015416
+                print 'Status: 401 Unauthorized'
         loginpage(mlist, doc, user, language)
         print doc.Format()
         return
diff -NEur messages/de/LC_MESSAGES/mailman.po messages/de/LC_MESSAGES/mailman.po
--- messages/de/LC_MESSAGES/mailman.po	2020-06-27 02:12:17.548000000 +0200
+++ messages/de/LC_MESSAGES/mailman.po	2022-03-29 01:55:20.774000000 +0200
@@ -4577,7 +4577,7 @@
 
 #: Mailman/Defaults.py:1809
 msgid "Esperanto"
-msgstr "Deutsch"
+msgstr "Esperanto"
 
 # Mailman/Defaults.py:773
 #: Mailman/Defaults.py:1810
diff -NEur NEWS NEWS
--- NEWS	2021-12-13 21:36:11.555000000 +0100
+++ NEWS	2023-05-22 21:58:09.582000000 +0200
@@ -5,6 +5,26 @@
 
 Here is a history of user visible changes to Mailman.
 
+2.1.40 (xx-xxx-xxxx)
+
+  i18n
+
+    - The German translation of `Esperanto` is fixed.  (LP: #1966685)
+
+  Bug Fixes and other patches
+
+    - Test for a valid header following a Unix From_ line in bin/cleanarch
+      has been improved.  (LP: #1957025)
+    - A 500 Internal Server Error when requesting the options page for a
+      non-member address on a list with private rosters is avoided.
+      (LP: #1961762)
+    - A possible list membership leak via the user options CGI is fixed.
+      (LP: #1968443)
+    - Another possible list membership leak via the user options CGI is fixed.
+      (LP: #2015416)
+    - Yet another possible list membership leak via the user options CGI is
+      fixed.  (LP: #2017813)
+
 2.1.39 (13-Dec-2021)
 
   Bug Fixes and other patches
