Cross-Site Request Forgery (CSRF) in modoboa/modoboa
Description
Cross-Site Request Forgery (CSRF) in GitHub repository modoboa/modoboa prior to 2.2.2.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A CSRF vulnerability in Modoboa prior to 2.2.2 allows attackers to perform a logout action without proper request validation.
Overview
CVE-2023-5690 is a Cross-Site Request Forgery (CSRF) vulnerability in the open-source mail hosting platform Modoboa, affecting versions prior to 2.2.2 [1]. The flaw exists in the logout functionality, where the dologout view was not restricted to POST requests, and the user_menu template tag passed the user object directly without requiring a POST method for the logout link [1]. This allowed an attacker to trigger a logout on behalf of an authenticated user by crafting a malicious link or form that the victim would visit.
Exploitation
An attacker can exploit this vulnerability by convincing an authenticated Modoboa user to click on a crafted URL or submit a hidden form. Since the logout endpoint did not enforce the POST method, a simple GET request or any cross-origin request could initiate the logout [1]. The fix introduced the @require_http_methods(["POST"]) decorator on the dologout view and changed the logout menu entry method to POST, preventing CSRF attacks [1].
Impact
Successful exploitation allows an attacker to forcefully log out a victim from their Modoboa session [1]. This can be used to interrupt the user's work, contribute to a denial-of-service condition, or as part of a social engineering chain that makes the user believe they must re-authenticate on a phishing site. The vulnerability does not directly expose data, but it can facilitate further attacks by disrupting the user's session.
Mitigation
The vulnerability was addressed in Modoboa version 2.2.2 by commit 23e4c255 [1]. Users should upgrade to this version or later to remediate the issue. The official advisory is available from huntr.dev and the PyPI advisory database [2][3]. Modoboa is an actively maintained project, and no workarounds have been provided for older versions [4].
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
modoboaPyPI | < 2.2.2 | 2.2.2 |
Affected products
2- modoboa/modoboa/modoboav5Range: unspecified
Patches
123e4c25511c6Merge pull request #3090 from modoboa/fix/csrf_issue_logout
6 files changed · +47 −20
modoboa/core/templatetags/core_tags.py+12 −8 modified@@ -79,11 +79,11 @@ def admin_menu(selection, user): @register.simple_tag -def user_menu(user, selection): +def user_menu(request, selection): entries = [ {"name": "user", "img": "fa fa-user", - "label": user.fullname, + "label": request.user.fullname, "menu": [ {"name": "settings", "img": "fa fa-list", @@ -93,17 +93,21 @@ def user_menu(user, selection): ] extra_entries = signals.extra_user_menu_entries.send( - sender="user_menu", location="options_menu", user=user) + sender="user_menu", location="options_menu", user=request.user) extra_entries = reduce( lambda a, b: a + b, [entry[1] for entry in extra_entries]) entries[0]["menu"] += ( - extra_entries + [{"name": "logout", - "url": reverse("core:logout"), - "label": _("Logout"), - "img": "fa fa-sign-out"}] + extra_entries + [{ + "name": "logout", + "url": reverse("core:logout"), + "label": _("Logout"), + "img": "fa fa-sign-out", + "method": "post" + }] ) return render_to_string("common/menulist.html", { - "selection": selection, "entries": entries, "user": user + "request": request, "selection": selection, + "entries": entries, "user": request.user })
modoboa/core/views/auth.py+2 −0 modified@@ -16,6 +16,7 @@ from django.utils.translation import gettext as _ from django.views import generic from django.views.decorators.cache import never_cache +from django.views.decorators.http import require_http_methods from django.contrib.auth import ( authenticate, login, logout, views as auth_views @@ -126,6 +127,7 @@ def dologin(request): dologin = never_cache(dologin) +@require_http_methods(["POST"]) def dologout(request): """Logout current user.""" if not request.user.is_anonymous:
modoboa/lib/templatetags/lib_tags.py+10 −1 modified@@ -3,7 +3,7 @@ from datetime import datetime from django import template -from django.template import Context, Template +from django.template import Context, RequestContext, Template from django.utils.safestring import mark_safe from django.utils.translation import gettext as _ @@ -51,6 +51,15 @@ def render_link(linkdef, mdclass=""): return t.render(Context({"link": linkdef, "mdclass": mdclass})) +@register.simple_tag +def render_post_link(linkdef, request): + t = Template("""<form method="post" action="{{ link.url }}"> +{% csrf_token %} +<a class="menu-link" href="#" onclick="this.parentNode.submit()">{% if link.img %}<i class="{{ link.img }}"></i>{% endif %}{{ link.label }}</a> +</form>""") + return t.render(RequestContext(request, {"link": linkdef})) + + @register.simple_tag def progress_color(value): value = int(value)
modoboa/static/css/custom.css+15 −7 modified@@ -1,6 +1,6 @@ /* ------- Media ------- */ -.sidebar { +.sidebar { display: none; } @@ -67,7 +67,7 @@ /* --------- general --------- */ -.container-fluid { +.container-fluid { padding-left: 0; padding-right: 0; } @@ -101,7 +101,7 @@ /* Global */ -body { +body { padding-top: 50px; padding-bottom: 50px; } @@ -168,7 +168,15 @@ label { table-layout: fixed; } - +.menu-link { + display: block; + padding: 3px 20px; + clear: both; + font-weight: 400; + line-height: 1.42857143; + color: #333; + white-space: nowrap; +} /* --------- main page --------- */ @@ -202,7 +210,7 @@ html body div.navbar div.container-fluid div#navigate-navbar-collapse.collapse u padding-left: 20px;*/ } -.nav-sidebar > li > a:hover { +.nav-sidebar > li > a:hover { background-color: #eee; } @@ -230,7 +238,7 @@ html body div.navbar div.container-fluid div#navigate-navbar-collapse.collapse u margin-bottom: 4px; } -.main { +.main { padding: 20px 15px; } @@ -280,7 +288,7 @@ table td[name="actions"] { /* modals */ -.modal-body .nav-pills { +.modal-body .nav-pills { margin-bottom: 15px; }
modoboa/templates/common/menulist.html+7 −3 modified@@ -4,19 +4,23 @@ <li class="divider"> </li> {% else %} {% if entry.menu %} - <li class="dropdown {{ entry.class }}{% if selection == entry.name %} active{% endif %}"> + <li class="dropdown {{ entry.class }}{% if selection == entry.name %} active{% endif %}"> <a class="dropdown-toggle" name="{{ entry.name }}" data-toggle="dropdown" href="{{ entry.url }}"> {% if entry.img %}<span class="{{ entry.img }}"></span> {% endif %}{{ entry.label }} </a> <ul class="dropdown-menu" {% if entry.width %}style="width: {{ entry.width }}px"{% endif %}> {% for sentry in entry.menu %} - <li>{% render_link sentry %}</li> + <li>{% if sentry.method == "post" %}{% render_post_link sentry request %}{% else %}{% render_link sentry %}{% endif %}</li> {% endfor %} </ul> </li> {% else %} <li class="{% if selection == entry.name %}active{% endif %}"> - {% render_link entry %} + {% if entry.method == "post" %} + {% render_post_link entry request %} + {% else %} + {% render_link entry %} + {% endif %} </li> {% endif %} {% endif %}
modoboa/templates/nlayout.html+1 −1 modified@@ -60,7 +60,7 @@ {% endif %} </ul> <ul class="nav navbar-nav navbar-right"> - {% if selection %}{% user_menu user selection %}{% else %}{% user_menu user "" %}{% endif %} + {% if selection %}{% user_menu request selection %}{% else %}{% user_menu request "" %}{% endif %} </ul> {% include "common/top_notifications.html" %} </div>
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-57cr-rq3f-ppmxghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-5690ghsaADVISORY
- github.com/modoboa/modoboa/commit/23e4c25511c66c0548da001236f47e19e3f9e4d9ghsaWEB
- github.com/pypa/advisory-database/tree/main/vulns/modoboa/PYSEC-2023-217.yamlghsaWEB
- huntr.com/bounties/980c75a5-d978-4b0e-9bcc-2b2682c97e01ghsaWEB
News mentions
0No linked articles in our index yet.