本卡屬 FR-082(母卡 CM-1636),唯一一棒。只掃不修。
掃 AI 聊天機器人這個套件(13 個檔、632 行)。使用者在系統裡打字問 AI,系統把訊息原封不動送給 Anthropic(Claude),拿回覆顯示給使用者;對話記錄存在 Redis,一小時沒動自動清掉。
要找的是:能不能看到別人的對話、能不能塞東西進別人的記錄、能不能無限次呼叫把公司的錢燒光、送出去的內容有沒有人管。
前面掃過的套件(公告、問題追蹤、通知)風險都在「誰能看誰的資料」。這支多了兩個別人沒有的風險:
這些是首腦讀過程式碼後認為最容易出事的地方,是思考起點不是檢查清單;全部未經驗證,以你實際讀到的為準。工具不會照這份清單走——前一個 arc(FR-081)的 I3/I4/I6 三棒,工具在範圍內都是零產出,真正的發現全是人工補查的。所以這份清單你要自己追。
session_id 由呼叫端隨便給,直接變成 Redis 的 key。(本棒最值得追的一條)api/ai_bot_route.py:58 取 payload.get('session_id') 只做 .strip(),然後 app/service/ai_bot_service.py:60 組成 chat_history:{user_id}:{session_id}。要追:塞冒號會怎樣(例如 session_id = "x:chat_history:999")?能不能跨到別人的 key 去讀或覆寫?長度有沒有上限?空字串、../、控制字元呢?Redis key 沒有跳脫機制,冒號在這裡是有意義的分隔符。ai_bot_route.py:57 只 .strip(),ai_bot_service.py:92 直接 history.append({"role": "user", "content": message}) 送給 Anthropic。要追:能不能貼一整份客戶資料進去(資料外洩面)?有沒有長度上限(成本面)?主專案的全站 body 上限(CM-1587 定 50MB)擋不擋得到這裡?max_tokens=4096、max_history_turns=20,但沒有任何頻率或次數控制。任何登入者可以無限次呼叫。要追:有沒有其他層(nginx、中介層)擋?沒有的話這是真的成本洞。plugin.py:223-224 用 type() 動態產生子類,把 auth_required 套到 post 與 delete 上。首腦已 grep 確認:整支 plugin.py 沒有任何 raise、AiBotAdapters 沒有 __post_init__ 驗證——與 jedi-issue 不同(那支 plugin.py:222-233 會 raise RuntimeError 拒絕掛載)。要驗:AiBotAdapters 是 dataclass 必填欄位,這道擋得住「傳 None」嗎?傳 auth_required=None 會怎樣——是啟動時炸掉(好),還是端點變成不用登入(很糟)?ai_bot_service.py:102-104:except Exception as e: logger.exception(f"Claude API error: {e}") 然後回一句固定中文。要追:Anthropic SDK 的例外物件裡會不會帶 API key 或完整 request?(FR-078 的 CM-1606 就是「密碼寫進 log」,同款要查。)注意 CLAUDE.md 紀律:報告只寫「在哪一行、什麼形狀」,不要把金鑰值寫進落地檔。api/ai/__init__.py:42 是 AiBotConfig(api_key=os.getenv("ANTHROPIC_API_KEY"))。要追:沒設時 Anthropic(api_key=None) 的行為(是啟動炸掉還是每次呼叫才失敗)?harness/dev_app.py:104 同款讀法,harness 有沒有寫死值?chat_history:{user_id}:{session_id},user_id 來自宿主注入的 current_user_id()(主專案是 get_user_context().id)。沒有任何 Redis 層的隔離。要追:current_user_id() 回 None 或 0 會怎樣?多租戶情境下不同租戶的同 id 使用者會不會撞 key?clear_history 只憑 session_id 就刪。 ai_bot_route.py:74-75 從 query string 取 session_id 直接刪。配合重點 ① 的 key 注入,要追能不能刪掉別人的對話記錄。harness/dev_app.py(116 行)——開發用的啟動殼。看有沒有寫死憑證、debug 開關、或會被誤帶進正式環境的設定。這類檔案是密鑰專項最常撈到東西的地方。plugin.py 是最大單檔(262 行),四個插槽(adapters/config/schema_extensions/mount_api)。mount_api=False 的逃生門會不會讓 route 不掛但 service 仍可經 DI 被別處呼叫?(FR-079 的 F13 就是這個形狀:AI 儀表板旁路不經 route 層守門。)