diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bf4d8f5df..c740ff220f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,8 @@ account (Griatch) - [Fix][issue4311]: SSH connection caused a traceback in protocol (Griatch) - Fix: Resolve a bug when loading on-demand-handler data from database (Griatch) -- Security: Potentially O(n2) regex exploit in rpsystem regex (Griatch) +- Security: Potential O(n2) regex exploit in rpsystem regex (Griatch) +- Security: Fix potential redirect vulnerability in character page redirect (Griatch) - Doc fixes (iLPdev, Griatch, CloudKeeper) [pull3420]: https://github.com/evennia/evennia/pull/3420 diff --git a/evennia/web/website/views/characters.py b/evennia/web/website/views/characters.py index 03cb3e9668..f9e4142b1d 100644 --- a/evennia/web/website/views/characters.py +++ b/evennia/web/website/views/characters.py @@ -10,19 +10,16 @@ from django.contrib.auth.mixins import LoginRequiredMixin from django.db.models.functions import Lower from django.http import HttpResponseRedirect from django.urls import reverse_lazy +from django.utils.encoding import iri_to_uri +from django.utils.http import url_has_allowed_host_and_scheme from django.views.generic import ListView from django.views.generic.base import RedirectView - from evennia.utils import class_from_module from evennia.web.website import forms from .mixins import TypeclassMixin -from .objects import ( - ObjectCreateView, - ObjectDeleteView, - ObjectDetailView, - ObjectUpdateView, -) +from .objects import (ObjectCreateView, ObjectDeleteView, ObjectDetailView, + ObjectUpdateView) class CharacterMixin(TypeclassMixin): @@ -125,6 +122,13 @@ class CharacterPuppetView(LoginRequiredMixin, CharacterMixin, RedirectView, Obje # Get the page the user came from next_page = self.request.GET.get("next", self.success_url) + # since next_page is untrusted input from the user, we need to check it's safe to + next_page = iri_to_uri(next_page) + if not url_has_allowed_host_and_scheme(url=next_page, + allowed_hosts={self.request.get_host()}, + require_https=self.request.is_secure()): + next_page = self.success_url + if char: # If the account owns the char, store the ID of the char in the # Django request's session (different from Evennia session!). @@ -136,6 +140,7 @@ class CharacterPuppetView(LoginRequiredMixin, CharacterMixin, RedirectView, Obje self.request.session["puppet"] = None messages.error(self.request, "You cannot become '%s'." % char) + return next_page