---
title: I1 檢查結果：跟 GitHub／GitLab 連線的部分
---

# I1 檢查結果：跟 GitHub／GitLab 連線的部分

> 檢查日期 2026-09-09｜耗時 47 分鐘｜對應卡片 CM-1613

---

## 🔴 一句話結論

**系統連 GitHub 的時候，沒有檢查對方是不是真的 GitHub——公司的 GitHub 密碼（存取權杖）可能被路上的人攔走。**

---

## 這一棒在檢查什麼

使用者在系統裡送「意見回饋」時，系統除了存在自己的資料庫，還可以**同時去 GitHub 或 GitLab 開一張真的問題單**。要去別人的網站開單，就得帶著公司的帳號密碼（叫做「存取權杖」）。

這一棒檢查的就是**這段連線過程安不安全**——25 個檔案。

---

## 找到什麼

| # | 嚴重度 | 這是什麼問題 | 出事會怎樣 | 要先有什麼才打得到 | 在哪裡 | 修正卡 |
|---|---|---|---|---|---|---|
| 1 | 🟡 中 | 連 GitHub 時，**系統不檢查對方是不是真的 GitHub**。等於有人拿一張假名片來，我們也照樣把密碼給他 | 網路上的中間人（例如在公用 Wi-Fi、或公司網路設備被入侵）可以**假冒 GitHub，把公司的 GitHub 存取權杖整個拿走**。之後他能用那把權杖讀寫公司所有的程式碼 | ① 管理員已在後台**開啟** GitHub 整合並填入權杖（**出貨預設是關的**）<br>② 攻擊者要能**站在伺服器對外連線的路徑上** | `github_issue_adapter.py` 第 43 行 | **CM-1632** |
| 2 | 🟡 中 | 同一個問題的另一處。這支是「共用的連線工廠」，成員查詢跟附件功能都會用到它 | 同上。**只修一處沒用**，權杖還是會從另一條路漏出去 | 同上 | `infra/github.py` 第 22 行 | **CM-1632** |
| 3 | 🟡 中<br>⚠️ 不在這次檢查範圍 | 很久以前有人把一個開發用的設定檔（裡面寫著 GitHub 和 GitLab 的密碼）提交進版控 | 拿得到程式碼倉庫的人，可以從舊紀錄裡把密碼挖出來。**不過這兩把密碼在 CM-1573 那次已經作廢了** | 讀得到程式碼倉庫，或拿得到 Nexus 上兩個舊版本的套件檔 | `jedi_issue/.env`（已從最新版刪掉，但舊紀錄還在） | 併入 **CM-1607** |

---

## 詳細說明

### 問題 1、2：連 GitHub 沒有檢查對方身分

**白話**：你上網買東西時，瀏覽器會檢查「這個網站是不是真的 PChome」，靠的是一張數位證書。這個檢查如果關掉，任何人都能假冒 PChome，而你會把信用卡號送給他。

我們的系統連 GitHub 時，**這個檢查被關掉了**：

```python
# jedi-issue/jedi_issue/infra/github.py 第 22 行
return Github(auth=auth, per_page=100, timeout=10, verify=False)
#                                                  ↑ 這個 False 就是「不檢查」

# jedi-issue/jedi_issue/infra/issue/adapter/github/github_issue_adapter.py 第 43 行
self.gh = Github(auth=auth, per_page=100, timeout=10, verify=False)
#                                                     ↑ 同一個問題
```

**兩處要一起修**：一支是共用的連線工廠（成員查詢、附件功能都走它），一支是問題單功能自己建的。只修一邊，權杖還是會從另一邊漏出去。

**檢查員已經驗證過這不是誤報**：他們追了 PyGithub 這個套件的內部程式碼六層，確認 `verify=False` 一路傳到最底層真的生效，而且**連環境變數都救不回來**。

**為什麼是「中」不是「高」**：
- 出貨時這個功能**預設是關的**（`04-seed-core.sql` 第 610 行寫著 `enable: false`、權杖是空字串，首腦已親自核對）
- 要打到，得先有管理員主動開啟並填入權杖
- 攻擊者還得剛好站在伺服器對外連線的路上

**但要記得一件事**：CM-1573 就是「這個模組的 GitHub 密碼外洩處置」——**這個模組的權杖外洩過一次了**。

**怎麼修**：拿掉 `verify=False` 就好。如果真的有「自己架的 GitHub 企業版 + 內部憑證」的需求（**要先查證有沒有，不要假設**），改成從設定檔讀憑證路徑，而不是關掉檢查。

**首腦另外查了一件報告沒查的**：**GitLab 那一側沒有同樣的問題**（`gitlab.py` 和兩支 GitLab 相關檔案都找不到 `verify=False`）。所以這是 GitHub 專屬的問題。

**這是本專案第四次犯同樣的錯**：CM-1560（LDAP）、CM-1565（Redis）、CM-1606（寄信），加上這次。**修法可以直接抄前三張卡。**

### 問題 3：舊的設定檔留在版控歷史裡

**白話**：有人把寫著密碼的設定檔提交進版控，後來刪掉了——**但版控會記住所有歷史**，刪掉只是「最新版看不到」，翻舊紀錄還是找得到。

**首腦查證的結果**：那個檔存在於三個舊提交（`b740989`、`74d9626`、`5e3b9a3`），由 `d6a8d09` 刪除。**歷史還在。**

**好消息**：這兩把密碼在 CM-1573 那次已經作廢了（決策者當時裁定「token 早已註銷」）。

**CM-1573 沒收乾淨的兩件事**：
1. **Nexus 上 0.0.14／0.0.15 兩個套件檔是否已下架**——那兩個版本把這個設定檔打包進去發布了。**程式碼查不到，要連 Nexus 才能確認。**
2. git 歷史還在——依決策者 2026-09-08 的裁定**不重寫歷史**（重寫會改動所有提交編號、影響每個下載過的人，而對已散出去的內容毫無補救效果）。

---

## 這份結果可信到什麼程度

**要分兩件事看。**

### 「這三條是真的嗎」→ ✅ 可信

三條發現**每一條都經過三個獨立檢查員投票，三票全過**。首腦另外自己打開檔案核對了行號，也自己查了 GitLab 那側沒有同樣問題。

**關於報告上那個 `unverified` 標記**：那不是「檢查失敗」的意思。它的原因欄寫著 `findings-refused`——意思是「第 3 條指的那個檔案已經從最新版刪掉了，工具找不到檔案所以拒絕把它寫進正式報告」。**投票本身是完整的**：9 票全數投出、沒有漏投、沒有半途中斷。

（對照組：FR-077 R1 那次是真的失敗——105 個檢查員全部掛掉、21 張票 0 張投出。兩者完全不同。）

### 「是不是只有這三條」→ ❌ 不可信

這次用的是**快篩模式**，不是徹底審查。25 個檔案裡有 9 個是幾乎空白的檔案，實際有內容的大約 16 個。工具也沒有留下「每個檔案都讀到結論」的紀錄。

**所以正確的說法是**：「這三條問題確實存在」，而不是「這 25 個檔只有這三個問題」。

---

## 執行概況（技術細節，工程師看的）

| 項目 | 數字 |
|---|---|
| 檢查範圍 | 25 個檔案 |
| 派出／回報的研究員 | 2 / 2 |
| 提出的候選問題 → 去除重複後 | 5 → 3 |
| 投票數 | 9（3 條 × 3 個檢查員） |
| 沒投到票的 | 0 |
| 投票中斷的 | 0 |
| 被檢查員降低嚴重度的 | 0 |
| 耗時 | 47 分鐘 |
