CVE-2025-62379
Description
Reflex is a library to build full-stack web apps in pure Python. In versions 0.5.4 through 0.8.14, the /auth-codespace endpoint automatically assigns the redirect_to query parameter value directly to client-side links without any validation and triggers automatic clicks when the page loads in a GitHub Codespaces environment. This allows attackers to redirect users to arbitrary external URLs. The vulnerable route is only registered when a Codespaces environment is detected, and the detection is controlled by environment variables. The same behavior can be activated in production if the GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN environment variable is set. The vulnerability occurs because the code assigns the redirect_to query parameter directly to a.href without any validation and immediately triggers a click (automatic navigation), allowing users to be sent to arbitrary external domains. The execution condition is based on the presence of a sessionStorage flag, meaning it triggers immediately on first visits or in incognito/private browsing windows, with no server-side origin/scheme whitelist or internal path enforcement defenses in place. This issue has been patched in version 0.8.15. As a workaround, users can ensure that GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN is not set in a production environment.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
reflexPyPI | >= 0.5.4, <= 0.8.14 | — |
Affected products
1Patches
1ade12549f3c0check domain before redirecting in codespaces (#5886)
1 file changed · +30 −1
reflex/utils/codespaces.py+30 −1 modified@@ -26,11 +26,40 @@ def redirect_script() -> str: const thisUrl = new URL(window.location.href); const params = new URLSearchParams(thisUrl.search) +function sameHostnameDifferentPort(one, two) {{ + const hostnameOne = one.hostname; + const hostnameTwo = two.hostname; + const partsOne = hostnameOne.split("."); + const partsTwo = hostnameTwo.split("."); + if (partsOne.length !== partsTwo.length) {{ return false; }} + for (let i = 1; i < partsOne.length; i++) {{ + if (partsOne[i] !== partsTwo[i]) {{ return false; }} + }} + const uniqueNameOne = partsOne[0]; + const uniqueNameTwo = partsTwo[0]; + const uniqueNamePartsOne = uniqueNameOne.split("-"); + const uniqueNamePartsTwo = uniqueNameTwo.split("-"); + if (uniqueNamePartsOne.length !== uniqueNamePartsTwo.length) {{ return false; }} + for (let i = 0; i < uniqueNamePartsOne.length - 1; i++) {{ + if (uniqueNamePartsOne[i] !== uniqueNamePartsTwo[i]) {{ return false; }} + }} + return true; +}} + function doRedirect(url) {{ if (!window.sessionStorage.getItem("authenticated_github_codespaces")) {{ const a = document.createElement("a"); if (params.has("redirect_to")) {{ - a.href = params.get("redirect_to") + const redirect_to = new URL(params.get("redirect_to")); + if (!sameHostnameDifferentPort(thisUrl, redirect_to)) {{ + console.warn("Reflex: Not redirecting to different hostname"); + return; + }} + if (!redirect_to.hostname.endsWith(".app.github.dev")) {{ + console.warn("Reflex: Not redirecting to non .app.github.dev hostname"); + return; + }} + a.href = redirect_to.href; }} else if (!window.location.href.startsWith(url)) {{ a.href = url + `?redirect_to=${{window.location.href}}` }} else {{
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-rfh5-c9h5-q8jmghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-62379ghsaADVISORY
- file.notion.so/f/f/d105d145-04bc-45c5-b46c-ed880895e9de/a86c3e3b-f67f-45d1-8fa2-4aa0ba7d0068/poc.mp4ghsaWEB
- github.com/reflex-dev/reflex/blob/51f9f2c2f52cac4d66c07683a12bc0237311b6be/reflex/utils/codespaces.pyghsaWEB
- github.com/reflex-dev/reflex/commit/ade12549f3c0ddab3d7382c581bc04a3c1f989ecnvdWEB
- github.com/reflex-dev/reflex/security/advisories/GHSA-rfh5-c9h5-q8jmnvdWEB
News mentions
0No linked articles in our index yet.