GHSA-gcwf-c25f-p9rv

Suggest an improvement
Source
https://github.com/advisories/GHSA-gcwf-c25f-p9rv
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/11/GHSA-gcwf-c25f-p9rv/GHSA-gcwf-c25f-p9rv.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-gcwf-c25f-p9rv
Aliases
  • CVE-2026-77433
Published
2026-11-09T23:24:14Z
Modified
2026-11-09T23:30:04Z
Severity
  • 6.1 (Medium) CVSS_V3 - CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N CVSS Calculator
Summary
Kiwi TCMS account confirmation open redirect through protocol-relative URLs
Details

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

Database specific
{
    "cwe_ids": [
        "CWE-601"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-11-09T23:24:14Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
}
References

Affected packages

PyPI / kiwitcms

Package

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Last Affected
12.4

Affected versions

6.*
6.2.1
6.3
6.4
6.5
6.5.3
6.6
6.7
6.8
6.9
6.10
6.11
7.*
7.0
7.1
7.2
7.2.1
7.3
8.*
8.0
8.1
8.1.99
8.2
8.3
8.4
8.5
8.6
8.6.1
8.7
8.8
8.9
9.*
9.0
9.999
10.*
10.0
10.1
10.2
10.3
10.3.999
10.4
10.5
11.*
11.0
11.1
11.3
11.4
11.5
11.6
11.7
12.*
12.0
12.1
12.2
12.3
12.4

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/11/GHSA-gcwf-c25f-p9rv/GHSA-gcwf-c25f-p9rv.json"