← 回到四專案比較

獨立審查 · 完整回覆

Clawdline 2.1.1

Clawdline 2.1.1 · Claude Code · 原生配對橋專項

2026-10-2296ad9d5e9 ↗僅讀公開網路

確切題目

請檢視這個版本的原生配對橋,有無資安風險?
題目附帶的固定版本連結 ↗

下方完整保留 agent 原始回覆,原文語言有明確標示。中文導讀是編輯整理,不是原文,也不是驗證結論。審查沒有執行安裝或攻擊測試。

中文導讀(編輯整理)

兩位審查者都在 hosted 頁面遭入侵的威脅模型下,指出原生確認流程的接收端綁定疑慮。這是靜態檢視發現,尚未重現攻擊;審查者也肯定來源檢查與本機 token 隔離。

這是另一次針對原生橋的專項檢視,題目為中文,不屬於上方 16 份英文題目的比較。

下載完整中文原文

完整中文原始回覆

我看完了這個 commit 的原生配對橋(shell/darwin/Pairing.swift、PairingDialogs.swift、CloudPairing.swift、Browser.swift)以及它呼叫的 daemon 端程式。結論是有一個重要問題要處理,另有幾個中低風險。WebView 的 origin 檢查本身寫得不錯。

先說明限制:我沒有 clone repo,是透過網頁抓取工具逐段讀程式。下面的結論都有對照原始碼片段,但 control plane 伺服器端、agent 啟動參數、requireLocal 的實作和 daemon 監聽的位址,我都沒看到。

1. 【高】CloudPairLocal 可以把帳號主金鑰交給任何 offer

流程是:Cloud 頁面呼叫 CloudPairLocal,原生端跳出確認框,使用者按同意後 POST 到 /v1/cloud/pairing/offer,進入 internal/transport/cloud/pairing.go 的 Complete(),再由 deliver() 把資料封給 offer 裡的金鑰。

  • Complete() 送出前只檢查三件事:offer 能 decode、還沒過期、offer.AccountID == p.AccountID。
  • offer 沒有簽章。internal/domain/cloud/pairing.go 只確認指紋和 offer 內的公鑰一致,註解自己也寫了 “The fingerprint is not authority”。
  • 不會檢查 offer 是否來自本機發出、還在等待中的邀請,也不會用 OpenEncryptedOffer 解開邀請密鑰。這兩個檢查只存在於另一條 answer() 路徑。
  • deliver() 封裝的 PairingHandover 含有 MasterSecret(帳號主金鑰或 content key)。
  • 確認框只顯示 daemon 回報的機器名稱,沒有任何可以讓兩台裝置互相比對的碼或指紋。相比之下,IdentityPairing 路徑有六位數比對碼。

影響: 如果 app.clawdline.com 被入侵、遭供應鏈污染,或營運方本身惡意,只要讓使用者在對話框按一次同意,就能拿到可以解密所有機器內容的金鑰。README 說「Cloud 只轉送密文」,這條路徑讓這個 E2E 承諾變成取決於那一次點擊。

建議: 貼上路徑也要求本機有對應的待處理邀請,或驗證邀請密鑰。確認框加上 offer 指紋或比對碼,並要求使用者在另一台裝置上核對。

2. 【中】CloudPairAgent 一鍵啟動 full 權限的 AI 助手

  • 核准後,daemon(cloud_agent.go 呼叫 orchestrator/detached_pairing.go)會啟動一個 "permission_mode": "full" 的助手。指令範本說明沒有人在看,它會執行 clawdline cloud pair -offer '%[3]s'。
  • Shell injection 目前擋得住。 DecodeCanonicalBase64URL 對每個字元做 [A-Za-z0-9_-] 白名單檢查,還會重新編碼比對,所以單引號進不去。但這個保護完全靠上游,DispatchPairingAgent 自己只檢查非空。建議改用環境變數或檔案傳遞 offer,或在 dispatch 時再驗證一次。
  • Prompt injection 的空間有限,但仍然存在。 machine_name 由頁面提供,經過清理,最多 64 字元並做 JSON 引號處理,但還是會被放進 full 權限 agent 讀的 prompt。
  • 確認框顯示 offer 的前 12 個字元,使用者其實無法用它判斷任何事。建議改顯示 daemon 驗證過的資訊。

3. 【中低】本機配對對話框

  • 預設按鈕給最高權限。 PairingDialogs.swift 的 chooseAlert 第一個按鈕是「讀取並操作」,按 Return 就會直接授予。建議預設改成「唯讀」或「忽略」。
  • 裝置名稱沒有清理。 notice.name 在 Swift 端沒有長度限制,也沒有過濾控制字元或 bidi 字元,會直接進入對話框標題和 shellLog。CLI 的 clawdline pair(cmd/clawdline/auth.go)也會原樣印到終端機,可能被 ANSI escape 注入或誤導。
  • 每次彈窗都會執行 NSApp.activate(ignoringOtherApps: true)。我沒看到有限速,可能被用來反覆搶焦點。

4. 【低】其他

  • CLAWDLINE_NEXT_CLOUD 環境變數可以把受信任的 Cloud origin 改成任意 http(s) 位址,release build 也沒有擋。前提是攻擊者已經能設定這個 App 的環境變數。
  • CloudPairLocal 的 status 不需要確認就會回傳 machine_id。Cloud 本來就知道這個值,影響可以忽略。
  • PairingPermissionClient 只把 / 從允許字元中移除,.. 不會被編碼。pairing_id 來自本機 daemon,所以風險很低。

做得好的部分

  • 兩個 handler 只註冊在 Cloud WebView 上。每次收到訊息都會檢查 isMainFrame、securityOrigin 的 scheme、host、port,以及 webView.url,subframe 和其他 origin 都會被拒絕。
  • 確認框關閉後會重新檢查 origin,防止期間頁面被換掉。
  • local token 用 HttpOnly、SameSite=Strict 的 cookie 注入,不出現在 URL 或頁面 script 中,log 裡也沒有 token 或 offer。
  • 設定寫入只接受本機 token,已配對的瀏覽器會收到 403。

建議優先處理第 1 點。 可以這樣驗證:用自己帳號的 AccountID,在沒有發出邀請的情況下產生一個 offer,看 /v1/cloud/pairing/offer 會不會成功交出主金鑰。也要確認 control plane 的 CompletePairing 有沒有檢查 PairingID 屬於這台機器,不過如果 Cloud 本身是威脅來源,這個伺服器端檢查也沒有保護作用。

← 回到比較表