From c0b7cf3415180f1dd86dc3a4bf231c8c08acbd8f Mon Sep 17 00:00:00 2001 From: Selig Date: Sun, 15 Mar 2026 15:01:41 +0800 Subject: [PATCH] improve(dispatch-webhook): enforce HTTPS for non-local webhook URLs --- skills/dispatch-webhook/SKILL.md | 1 + skills/dispatch-webhook/handler.ts | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/skills/dispatch-webhook/SKILL.md b/skills/dispatch-webhook/SKILL.md index a29b9ef..b5ca580 100644 --- a/skills/dispatch-webhook/SKILL.md +++ b/skills/dispatch-webhook/SKILL.md @@ -112,3 +112,4 @@ Task ID: {task_id} | 401 Unauthorized | 立即失敗,提示設定 token | | 超時(> 30s) | 返回 accepted,等待 callback | | VPS 回傳 500 | 記錄錯誤,通知使用者 | +| 非 HTTPS Webhook(且非 localhost/127.0.0.1) | 直接拒絕,避免 Bearer Token 明文傳輸 | diff --git a/skills/dispatch-webhook/handler.ts b/skills/dispatch-webhook/handler.ts index 2712ea9..504f975 100644 --- a/skills/dispatch-webhook/handler.ts +++ b/skills/dispatch-webhook/handler.ts @@ -51,6 +51,13 @@ function validateInput(raw: any): DispatchInput { throw new Error('Webhook URL 協定不支援,僅允許 http 或 https'); } + // 安全預設:正式環境僅允許 HTTPS,避免 Bearer Token 明文傳輸 + // 本機開發保留 http://localhost 與 http://127.0.0.1 例外 + const isLocalhost = ['localhost', '127.0.0.1'].includes(parsedUrl.hostname); + if (parsedUrl.protocol !== 'https:' && !isLocalhost) { + throw new Error('Webhook URL 安全性不足:非本機位址必須使用 https'); + } + if (!input.webhookToken || typeof input.webhookToken !== 'string') { throw new Error(`${input.target.toUpperCase()} Webhook Token 未設定`); }