diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 7e6fa1e4..2dd59082 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -73,6 +73,12 @@ jobs: with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} + config: | + paths-ignore: + # Third-party packages (vendored from external sources) + - 'package/@stackframe/**' + - 'node_modules/**' + - '**/node_modules/**' # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. diff --git a/server/app/controller/oauth/oauth_controller.py b/server/app/controller/oauth/oauth_controller.py index ce9b6104..a93ca5fb 100644 --- a/server/app/controller/oauth/oauth_controller.py +++ b/server/app/controller/oauth/oauth_controller.py @@ -13,12 +13,17 @@ # ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= import logging +import re +from urllib.parse import quote, urlencode from fastapi import APIRouter, HTTPException, Request from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse from app.component.oauth_adapter import OauthCallbackPayload, get_oauth_adapter +# Allowed OAuth provider names (alphanumeric and hyphens only) +ALLOWED_PROVIDER_PATTERN = re.compile(r"^[a-zA-Z0-9_-]+$") + logger = logging.getLogger("server_oauth_controller") router = APIRouter(prefix="/oauth", tags=["Oauth Servers"]) @@ -49,29 +54,53 @@ def oauth_login(app: str, request: Request, state: str | None = None): @router.get("/{app}/callback", name="OAuth Callback") -def oauth_callback(app: str, request: Request, code: str | None = None, state: str | None = None): +def oauth_callback( + app: str, + request: Request, + code: str | None = None, + state: str | None = None, +): """Handle OAuth provider callback and redirect to client app.""" + # Security: Validate provider name to prevent injection + if not ALLOWED_PROVIDER_PATTERN.match(app): + logger.warning( + "OAuth callback invalid provider name", + extra={"provider": app[:50]}, # Truncate for logging + ) + raise HTTPException(status_code=400, detail="Invalid provider") + if not code: logger.warning("OAuth callback missing code", extra={"provider": app}) raise HTTPException(status_code=400, detail="Missing code parameter") - logger.info("OAuth callback received", extra={"provider": app, "has_state": state is not None}) + logger.info( + "OAuth callback received", + extra={"provider": app, "has_state": state is not None}, + ) - redirect_url = f"eigent://callback/oauth?provider={app}&code={code}&state={state}" - html_content = f""" - -
-Redirecting, please wait...
- - - - """ + # Security: URL-encode all parameters to prevent XSS + params = {"provider": app, "code": code} + if state is not None: + params["state"] = state + redirect_url = f"eigent://callback/oauth?{urlencode(params)}" + + # Security: Use a safe redirect approach without embedding in JavaScript + # The redirect URL uses a custom protocol, so we encode it safely + safe_redirect_url = quote(redirect_url, safe=":/&?=") + + html_content = f""" + + + +Redirecting, please wait...
+If you are not redirected, click here.
+ + +""" return HTMLResponse(content=html_content)