fix: validate host URL in GitHub integration OAuth callback by nimish-ks · Pull Request #806 · phasehq/console
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/backend/api/views/auth.py b/backend/api/views/auth.py
--- a/backend/api/views/auth.py
+++ b/backend/api/views/auth.py
@@ -43,6 +43,7 @@
from ee.authentication.sso.oidc.okta.views import (
OktaOpenIDConnectAdapter,
)
+from urllib.parse import urlparse
CLOUD_HOSTED = settings.APP_HOST == "cloud"
@@ -205,17 +206,28 @@
state = json.loads(state_decoded)
original_url = state.get("returnUrl", "/")
+ # Sanitize original_url to ensure it is a safe relative path
+ if not isinstance(original_url, str):
+ original_url = "/"
+ original_url = original_url.replace("\\", "")
+ parsed_original = urlparse(original_url)
+ if parsed_original.scheme or parsed_original.netloc or original_url.startswith("//"):
+ safe_original_url = "/"
+ else:
+ # Ensure it starts with a slash to keep redirection within the app
+ safe_original_url = original_url if original_url.startswith("/") else f"/{original_url}"
+
if error:
# User denied the OAuth consent
return redirect(
- f"{os.getenv('ALLOWED_ORIGINS')}{original_url}?error=access_denied"
+ f"{os.getenv('ALLOWED_ORIGINS')}{safe_original_url}?error=access_denied"
)
code = request.GET.get("code")
if not code:
# Something went wrong (missing code)
return redirect(
- f"{os.getenv('ALLOWED_ORIGINS')}{original_url}?error=missing_code"
+ f"{os.getenv('ALLOWED_ORIGINS')}{safe_original_url}?error=missing_code"
)
is_enterprise = bool(state.get("isEnterprise", False))
@@ -225,20 +228,19 @@
name = state.get("name")
# Validate host_url to prevent SSRF
- from urllib.parse import urlparse
from api.utils.network import validate_url_is_safe
parsed = urlparse(host_url)
if parsed.scheme not in ("https", "http"):
return redirect(
- f"{os.getenv('ALLOWED_ORIGINS')}{original_url}?error=invalid_host_url"
+ f"{os.getenv('ALLOWED_ORIGINS')}{safe_original_url}?error=invalid_host_url"
)
try:
validate_url_is_safe(host_url)
except Exception:
return redirect(
- f"{os.getenv('ALLOWED_ORIGINS')}{original_url}?error=invalid_host_url"
+ f"{os.getenv('ALLOWED_ORIGINS')}{safe_original_url}?error=invalid_host_url"
)
client_id = (
@@ -267,10 +258,10 @@
access_token = response.json().get("access_token")
if not access_token:
return redirect(
- f"{os.getenv('ALLOWED_ORIGINS')}{original_url}?error=token_exchange_failed"
+ f"{os.getenv('ALLOWED_ORIGINS')}{safe_original_url}?error=token_exchange_failed"
)
store_oauth_token("github", name, access_token, host_url, api_url, org_id)
# Redirect back to Next.js app
- return redirect(f"{os.getenv('ALLOWED_ORIGINS')}{original_url}")
+ return redirect(f"{os.getenv('ALLOWED_ORIGINS')}{safe_original_url}")
EOF