fix(gateway): sanitize agent error messages, validate webhook gh args

Two of the three fixes from PR #6660 (the cli.py reopen_session change is
moot — that raw _conn.execute reopen block no longer exists on main).

- gateway/run.py: stop sending raw type(e).__name__ and str(e)[:300] to
  end users on chat platforms. Exception text from LLM providers can leak
  API URLs, file paths, and partial credentials. Return a generic message;
  keep curated status hints for known HTTP codes; full detail stays in logs.
- gateway/platforms/webhook.py: validate pr_number (positive int) and repo
  (owner/name regex) before passing to the 'gh pr comment' subprocess.
  Payload-controlled values could otherwise inject gh flags (--help, a
  different --repo). List-form subprocess means this is arg injection, not
  shell injection, but validation is still correct.

Co-authored-by: aaronagent <1115117931@qq.com>
This commit is contained in:
aaronagent 2026-06-28 15:25:25 -07:00 committed by Teknium
parent ec148f5d31
commit 27ddd8fd80
2 changed files with 25 additions and 6 deletions

View file

@ -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",

View file

@ -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: