---
id: "CVE-2026-77433"
page: "https://infrastack.ai/live/CVE-2026-77433"
kind: "vulnerability"
aliases: ["CVE-2026-77433", "GHSA-gcwf-c25f-p9rv"]
title: "Kiwi TCMS account confirmation open redirect through protocol-relative URLs"
severity: "medium"
cvss: 6.1
epss: null
exploited: false
status: "open"
category: "package"
products: [{"name": "kiwitcms", "fixed": [], "affected": "<= 12.4", "ecosystem": "pypi"}]
ecosystems: ["pypi"]
tags: ["cwe-601", "django", "kiwitcms", "package", "python", "self-hosted"]
not_affected_if: ["fixed-version", "no-open-registration"]
published_at: "2026-11-09T23:24:14+00:00"
first_seen_at: "2026-11-09T23:28:35+00:00"
updated_at: "2026-11-09T23:29:27+00:00"
sources: [{"source": "ghsa", "url": "https://github.com/advisories/GHSA-gcwf-c25f-p9rv", "first_seen_at": "2026-11-09T23:28:35+00:00"}]
exploit_sources: []
---

# Kiwi TCMS account confirmation open redirect through protocol-relative URLs

Link for people: https://infrastack.ai/live/CVE-2026-77433 (this .md is for agents)

The account confirmation endpoint in Kiwi TCMS checks that the redirect target starts with a slash, which lets protocol-relative URLs like //evil.com through. An attacker can send a crafted confirmation link that sends the user to a phishing or malware site after they confirm their account.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- pypi:kiwitcms affected <= 12.4 fixed no fixed version listed

## How to check

- Check the installed version: `pip show kiwitcms` and compare it with the fixed version.
- Look at `tcms/kiwi_auth/views.py` in the `Confirm` view for a `startswith("/")` check on the `next` parameter.

## Fix

- `kiwitcms` fixed in `16.2`

## Timeline

- 2026-11-09T23:28:35+00:00 ghsa https://github.com/advisories/GHSA-gcwf-c25f-p9rv

## Documents

- [advisory] Maintainer's advisory: api.github.com https://api.github.com/repos/kiwitcms/Kiwi/security-advisories/GHSA-gcwf-c25f-p9rv
- [advisory] Maintainer's advisory: github.com https://github.com/kiwitcms/Kiwi/security/advisories/GHSA-gcwf-c25f-p9rv
- [advisory] Maintainer's advisory: github.com https://github.com/kiwitcms/Kiwi/security/advisories/GHSA-hmj5-jm8h-h9fh
- [fix] Patch: github.com https://github.com/kiwitcms/Kiwi/pull/4458
- [fix] Patch: github.com https://github.com/kiwitcms/Kiwi/commit/65d8f7c2743d7f06a4fca77c060b9d561f02f948
- [fix] Release: github.com https://github.com/kiwitcms/Kiwi/releases/tag/v16.2

## From the sources

## Summary

In Kiwi TCMS version 16.1, the fix for CVE-2026-54724 (open redirect via unvalidated `next` parameter) in the account confirmation endpoint is incomplete. The validation uses `startswith("/")` to check if the redirect URL is local, but this is bypassed by protocol-relative URLs like `//evil.com` which start with `/` but redirect the browser to an external attacker-controlled domain. 16.1’s incomplete mitigation still allows protocol-relative destinations and earlier releases lack the mitigation.

## Vulnerable Code

In `tcms/kiwi_auth/views.py`, the `Confirm` view (line ~113):

    def get_redirect_url(self, *args, **kwargs):
        self.url = self.request.GET.get("next", reverse("core-views-index"))
        if not self.url.startswith("/"):
            self.url = reverse("core-views-index")

The check `startswith("/")` passes for `//evil.com` because it begins with `/`, but browsers interpret `//evil.com` as a protocol-relative URL that redirects to `https://evil.com` (or `http://evil.com` depending on the current page's protocol).

## Proof of Concept

    GET /confirm/<activation_key>/?next=//evil.com/phishing HTTP/1.1
    Host: kiwi.example.com

Response:

    HTTP/1.1 302 Found
    Location: //evil.com/phishing

The browser follows the redirect to `https://evil.com/phishing`.

Verification:

    >>> url = "//evil.com/phishing"
    >>> url.startswith("/")
    True  # passes the check!

## Impact

An attacker can craft a confirmation link that, after the user confirms their account, redirects them to a phishing page. This is useful for:

- Credential phishing (fake login page on attacker domain)
- Malware delivery after trusted action
- Social engineering (user trusts the link because it's from the legitimate Kiwi TCMS instance)

The attack requires sending a crafted activation link to a user who is registering, or intercepting/predicting the activation key.

## Suggested Fix

Use Django's `url_has_allowed_host_and_scheme()` utility instead of a simple `startswith` check:

    from django.utils.http import url_has_allowed_host_and_scheme

    def get_redirect_url(self, *args, **kwargs):
        self.url = self.request.GET.get("next", reverse("core-views-index"))
        if not url_has_allowed_host_and_scheme(
            self.url,
            allowed_hosts={self.request.get_host()},
            require_https=self.request.is_secure(),
        ):
            self.url = reverse("core-views-index")

This properly rejects protocol-relative URLs, absolute URLs to other hosts, and other bypass patterns.

Fixed in Version 16.2

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
