← Back to the comparison

Independent review · Full response

Clawdline 2.1.1

Clawdline 2.1.1 · Claude Code · Native pairing bridge

2026-10-2296ad9d5e9 ↗Public-web access only

Exact prompt

請檢視這個版本的原生配對橋,有無資安風險?
Pinned repository link supplied with the question ↗

The text below is the agent’s complete original response, with its original language identified. The introduction is editorial, not part of the original output or an independently verified conclusion. No installation or attack testing was performed.

Editorial introduction

Both reviewers flagged recipient binding in the native confirmation flow under a compromised hosted-page threat model. This is a static finding, not a reproduced exploit. Origin checks and local-token isolation were recognized as useful controls.

This is a separate bridge-specific review with a Chinese prompt, outside the 16 English-prompt comparison responses.

Download the complete Chinese original

Complete original response (Traditional Chinese)

我看完了這個 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 本身是威脅來源,這個伺服器端檢查也沒有保護作用。

← Back to the comparison