Headline
CVE-2021-46898: Update switch.py · sehmaschine/django-grappelli@4ca94bc
views/switch.py in django-grappelli (aka Django Grappelli) before 2.15.2 attempts to prevent external redirection with startswith(“/”) but this does not consider a protocol-relative URL (e.g., //example.com) attack.
Expand Up @@ -8,6 +8,7 @@ from django.http import Http404 from django.shortcuts import redirect from django.utils.html import escape from django.utils.http import url_has_allowed_host_and_scheme from django.utils.translation import gettext_lazy as _
from grappelli.settings import SWITCH_USER_ORIGINAL, SWITCH_USER_TARGET Expand All @@ -28,30 +29,35 @@ def switch_user(request, object_id):
# check redirect redirect_url = request.GET.get("redirect", None) if redirect_url is None or not redirect_url.startswith(“/”): if redirect_url is None or not \ url_has_allowed_host_and_scheme( url=redirect_url, allowed_hosts={request.get_host()}, require_https=request.is_secure(), ): raise Http404()
# check original_user try: original_user = User.objects.get(pk=session_user[“id”], is_staff=True) if not SWITCH_USER_ORIGINAL(original_user): messages.add_message(request, messages.ERROR, _(“Permission denied.”)) return redirect(request.GET.get(“redirect”)) return redirect(redirect_url) except ObjectDoesNotExist: msg = _(‘%(name)s object with primary key %(key)r does not exist.’) % {’name’: "User", 'key’: escape(session_user[“id”])} messages.add_message(request, messages.ERROR, msg) return redirect(request.GET.get(“redirect”)) return redirect(redirect_url)
# check new user try: target_user = User.objects.get(pk=object_id, is_staff=True) if target_user != original_user and not SWITCH_USER_TARGET(original_user, target_user): messages.add_message(request, messages.ERROR, _(“Permission denied.”)) return redirect(request.GET.get(“redirect”)) return redirect(redirect_url) except ObjectDoesNotExist: msg = _(‘%(name)s object with primary key %(key)r does not exist.’) % {’name’: "User", 'key’: escape(object_id)} messages.add_message(request, messages.ERROR, msg) return redirect(request.GET.get(“redirect”)) return redirect(redirect_url)
# find backend if not hasattr(target_user, ‘backend’): Expand All @@ -66,4 +72,4 @@ def switch_user(request, object_id): if original_user.id != target_user.id: request.session[“original_user”] = {"id": original_user.id, "username": original_user.get_username()}
return redirect(request.GET.get(“redirect”)) return redirect(redirect_url)
Related news
views/switch.py in django-grappelli (aka Django Grappelli) before 2.15.2 attempts to prevent external redirection with startswith("/") but this does not consider a protocol-relative URL (e.g., //example.com) attack.