diff --git a/gateway/platforms/webhook.py b/gateway/platforms/webhook.py index 7c77a96b5b8..9d236f2198b 100644 --- a/gateway/platforms/webhook.py +++ b/gateway/platforms/webhook.py @@ -938,13 +938,34 @@ class WebhookAdapter(BasePlatformAdapter): success=False, error="Missing repo or pr_number" ) + # --- Input validation (prevent CLI argument injection) --- + # pr_number must be a positive integer. + try: + pr_int = int(pr_number) + if pr_int <= 0: + raise ValueError("non-positive") + except (ValueError, TypeError): + logger.error( + "[webhook] invalid pr_number: %r", pr_number + ) + return SendResult( + success=False, error="Invalid pr_number" + ) + + # repo must match owner/name (alphanumeric, hyphens, underscores, dots). + if not re.fullmatch(r"[A-Za-z0-9._-]+/[A-Za-z0-9._-]+", repo): + logger.error("[webhook] invalid repo format: %r", repo) + return SendResult( + success=False, error="Invalid repo format" + ) + try: result = subprocess.run( [ "gh", "pr", "comment", - str(pr_number), + str(pr_int), "--repo", repo, "--body", diff --git a/gateway/run.py b/gateway/run.py index d449bdcf9f4..c32fbff0c87 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -10910,8 +10910,8 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew ) except Exception: logger.debug("Failed to persist inbound user message after agent exception", exc_info=True) - error_type = type(e).__name__ - error_detail = str(e)[:300] if str(e) else "no details available" + # Log full details server-side only; never expose raw exception + # types or messages to end users (info-leakage risk). status_hint = "" status_code = getattr(e, "status_code", None) _hist_len = len(history) if 'history' in locals() else 0 @@ -10955,9 +10955,7 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew elif status_code == 400: status_hint = " The request was rejected by the API." return ( - f"Sorry, I encountered an error ({error_type}).\n" - f"{error_detail}\n" - f"{status_hint}" + f"Sorry, I encountered an unexpected error.{status_hint}\n" "Try again or use /reset to start a fresh session." ) finally: