Logged-in user can unsubscribe anyone from any list using specially crafted POST request (CVE-2021-40347)
I'm forwarding this security report from Kevin Israel (Wikipedia user PleaseStand), who discovered this on lists.wikimedia.org and filed a reporti n our tracker: https://phabricator.wikimedia.org/T289798. Using a specially crafted POST request, a logged-in user can unsubscribe anyone from any list.
- Subscribe to a mailing list with address A and confirm the subscription
- Create an account using address B, and visit a mailing list page that you are not subscribed to, you should see the subscription form and an address dropdown.
- Using your browsers inspector, change the form's URL by replacing
- Change the
nameattribute on the address
- Change the value of the selected option to be address A.
- Click the "Subscribe" button.
You'll see that address A has now been unsubscribed. Additionally, address B now knows that A was subscribed to the list, allowing for leaking the subscriber list as they'd receive an error like ""email@example.com is not a member address of ..." if A was not subscribed.
The cause is https://gitlab.com/mailman/postorius/-/blob/master/src/postorius/views/list.py#L553, which does not verify the user owns the email address being unsubscribed.
Here's a patch that I've tested works functionally and deployed to lists.wikimedia.org:
diff --git a/src/postorius/views/list.py b/src/postorius/views/list.py index f03f1c13..1864c71f 100644 --- a/src/postorius/views/list.py +++ b/src/postorius/views/list.py @@ -553,6 +553,15 @@ class ListUnsubscribeView(MailingListView): @method_decorator(login_required) def post(self, request, *args, **kwargs): email = request.POST['email'] + # Verify the user actually controls this email + user_emails = EmailAddress.objects.filter( + user=request.user, verified=True).order_by( + "email").values_list("email", flat=True) + if email not in user_emails: + messages.error( + request, + _('You can only unsubscribe yourself.')) + return redirect('list_summary', self.mailing_list.list_id) if self._has_pending_unsub_req(email): messages.error( request,
I copied the user_emails chunk from earlier in this file to make sure I didn't implement the query wrong. If that looks good I can add the news entry, etc. and submit a MR - let me know.