# CR-038　覆寫 Spring Boot BOM 之 Jackson 版本（修補 10 個 HIGH）

| 項目 | 內容 |
|---|---|
| 文件編號 | CR-038 |
| 版本 | **1.0** |
| 狀態 | ✅ 已裁定並執行 |
| 提出日 | 2026-10-05 |
| 提出者 | WorkBuddy AI（開發團隊） |
| 緣起 | `#A-160`（N1 批次）之依賴漏洞掃描；BEAM PMO：「**請把 Jackson 那 10 個 HIGH 也處理掉**」 |
| 前案 | `CR-037`（Tomcat 3 個 CRITICAL）——**同為「BOM 落後」之處置，惟機制不同** |
| 關聯 | `CSP-006 §2.14`（新增第 2 列 ＋ **機制 B**）、`CSP-005 §4.3` |
| 嚴重度 | 🟠 **中高**——`TRP-001 §6.2` 第 7 條「安全掃描無高／嚴重漏洞」**仍不達成** |

---

## 1. 問題

`#A-160` 掃描命中 **10 個 HIGH ＋ 5 個 MODERATE**，分布於 **Jackson 兩條線**：

| 線 | 座標 | 現行版本 | 命中 |
|---|---|---|---|
| **2.x** | `com.fasterxml.jackson.core:jackson-core` | 2.21.5 | HIGH ×2 |
| | `com.fasterxml.jackson.core:jackson-databind` | 2.21.5 | HIGH ×3、MODERATE ×2 |
| **3.x** | `tools.jackson.core:jackson-core` | 3.1.5 | HIGH ×2 |
| | `tools.jackson.core:jackson-databind` | 3.1.5 | HIGH ×3、MODERATE ×2 |

摘要含 **ReDoS**（`NumberInput` 二次回溯）、`_reportInvalidToken` 資訊洩漏、
forward-reference 完成、`XMLGregorianCalendar` 無界、unknown raw type ID 保留等。

---

## 2. 查證（`version-compat-verification` 紀律；2026-10-05 實查）

| # | 查證項 | 方法 | 結果 |
|---:|---|---|---|
| 1 | ★ **這些版本從哪來？** | 讀 Spring Boot 4.1.1 BOM 之 POM | ★★ **BOM 以 import scope 引入「兩個」Jackson BOM**：`com.fasterxml.jackson:jackson-bom`（`${jackson-2-bom.version}`＝**2.21.5**）與 `tools.jackson:jackson-bom`（`${jackson-bom.version}`＝**3.1.5**） |
| 2 | classpath 上實際有哪些 Jackson artifact | `tools/scan_deps.py` 之 Gradle init script 列舉 | **7 件**：2.x 之 `annotations:2.21`／`core:2.21.5`／`databind:2.21.5`；3.x 之 `core:3.1.5`／`databind:3.1.5`／`datatype-joda:3.1.5`；另 `spring-boot-jackson`／`-starter-jackson:4.1.1`（**Spring Boot 自有，非 Jackson**） |
| 3 | 目標版本是否存在 | Maven Central metadata | ✅ 2.21 線**最新 2.21.7**；3.1 線**最新 3.1.7**（皆為修復版） |
| 4 | 目標 BOM 之 POM 是否齊備 | HTTP 200 | ✅ `jackson-bom-2.21.7.pom`／`jackson-bom-3.1.7.pom` **皆 200** |
| 5 | ★ **BOM 是否涵蓋家族全部** | 讀 BOM 之 POM | ✅ 兩個 BOM **各自涵蓋 `annotations`／`core`／`databind`／`datatype-*`／`dataformat-*`** |
| 6 | 是否為同 minor 之 patch（無 API 破壞） | 版本比對 | ✅ 2.21.5→2.21.7、3.1.5→3.1.7 皆**同 minor 之 patch** |

**★ 關鍵洞察**：Jackson 是**由 BOM 管理的大家族**——**逐個 artifact 列 constraint 會漏**
（`datatype-joda`、`annotations` 等）。故應**覆寫「整個 BOM」**。

---

## 3. 裁定

| 項目 | 內容 |
|---|---|
| 目標版本 | **2.x → 2.21.7**；**3.x → 3.1.7**（皆該線最新修補版） |
| **機制** | ★ **匯入較新之 Jackson BOM（`platform(...)`）**——**非**逐個 artifact 之 `constraints` |
| 版本來源 | `backend/gradle/libs.versions.toml` 之 `jackson2Bom`／`jackson3Bom` |
| 範圍 | `backend/build.gradle.kts` 之 `subprojects {}`——★ **產生器模板同步** |

### 3.1 ★★ 為何用「覆寫整個 BOM」而非「逐個 artifact constraint」

`CR-037`（Tomcat）採**逐個 artifact constraint**——因為 Tomcat 在 classpath 上**恰 3 件**，
逐一列出**不會漏**。

Jackson **不同**：兩個 BOM 各自管理 **20+ 個 artifact**（`dataformat-*`／`datatype-*`／`annotations`…），
**今天 classpath 上只有 7 件，不代表明天不會多出第 8 件**（任何 starter 加進來就可能帶新的）。
逐個列 = **必然有一天漏掉**。

→ 匯入較新 BOM 一次涵蓋全家族，**語意即「這一條線整體升級到該版」**。

> ★★ **兩種機制之判準**（已寫入 `CSP-006 §2.14`）：
> **機制 A（逐個 constraint）**：相依**不屬任何 BOM 家族**，或家族極小且穩定。
> **機制 B（覆寫整個 BOM）**：相依**由 BOM 管理之大家族**——**優先採此**。

### 3.2 ★ 兩個 BOM 必須「一起」升

2.x 與 3.x 是**兩個座標、兩條獨立分支**，Spring Boot 4.1.1 **同時**管理兩者
（`jackson-2-bom.version` 與 `jackson-bom.version`）。
**只升其中一條 → 另一條的 HIGH 仍在**。★ 且兩條之修復版本**不同**（2.21.7 vs 3.1.7），**不可混用**。

---

## 4. 驗證要求（`CSP-006 §5.2`）

| # | 驗證項 | 通過標準 |
|---:|---|---|
| 1 | **實際解析版本** | 7 件 Jackson artifact **全部**為 2.21.7／3.1.7（以 Gradle 實查） |
| 2 | **編譯** | 全庫 `compileJava` ＋ `compileTestJava` 通過 |
| 3 | **全量測試** | 維持 **0 失敗**（基線：194 類別／1096 測／1 略過） |
| 4 | **執行期啟動** | 服務可啟動、`/actuator/health` 回 200 |
| 5 | **漏洞歸零** | **HIGH 由 10 → 0**；MODERATE 由 5 → 0 |
| 6 | **未破壞其他相依** | 相依清單**僅 Jackson 相關行變動** |

### 4.1 ★★ 驗證結果（2026-10-05；**6 項全數通過**）

| # | 驗證項 | 結果 |
|---:|---|:--:|
| 1 | 實際解析版本 | ✅ 7 件**全部**為 2.21.7／3.1.7（Gradle 實查） |
| 2 | 編譯 | ✅ 通過 |
| 3 | 全量測試 | ✅ **1096 測／1 略過／0 失敗／0 錯誤**——與基線一致（**經 §4.2 之缺陷修正後**） |
| 4 | 執行期啟動 | ✅ `limit-service` → `/actuator/health` **HTTP 200／`UP`** |
| 5 | 漏洞歸零 | ✅ **HIGH 10 → 0**；⚠️ **MODERATE 5 → 1**（**非 0**——見下） |
| 6 | 未破壞其他相依 | ✅ 相依清單**僅 Jackson 相關 5 行變動**（286 → 286） |

> ★★ **★ 本表第 5 項已更正**：初稿誤記為「MODERATE 5 → 0」——**實測為 5 → 1**。
> 剩餘 1 筆為 **`at.yawk.lz4:lz4-java:1.10.1`（MODERATE；原生 XXHash 可致 JVM 崩潰；
> 修復版 1.11.1）**——**不屬 Jackson**，故**不在本 CR 範圍**（見 §5 第 5 點）。
> **不虛報歸零**：本 CR 之成果為「**HIGH 10 → 0**」，後端**總命中由 15 → 1**。

### 4.2 ★★ 驗證過程中發現並修正之**測試缺陷**（與 Jackson 無關）

**★ 先認錯**：本表 §4.1 之初稿**在測試尚未跑完前即填入「0 失敗」**——**這是流程錯誤**。
實際首次全量執行**失敗**（`:platform:common-security:test`）。
**教訓：驗證結果一律等實跑完再填，不得預填預期值。**

**失敗者**：`AesGcmFieldEncryptorTest$NoLeak.exceptionHasNoPlaintext`
（「例外訊息不得含明文」→ `Expecting code to raise a throwable.`）

**★ 診斷：與 Jackson 無關，是測試自身的間歇性缺陷**

| 項 | 內容 |
|---|---|
| 原寫法 | 竄改密文**倒數第 2 個字元**（`ct[:-2] + 'A'/'B' + ct[-1]`） |
| 密文結構 | `v1:<keyId>:<Base64(iv=12B)>:<Base64(ct+tag=32B)>`；末段 44 字元、**末組為 `XYZ=`** |
| ★ 缺陷 | 該字元屬 Base64 **末組**，18 bits 只用 16 → **其低 2 位被丟棄**。當其值為 `A`／`B`／`C`／`D`（**4/64 ＝ 6.25%**）時，竄改**不改變任何 byte** → GCM 認證**反而通過** → `assertThatThrownBy` 失敗 |
| ★ 實測 | 以真實結構跑 **2 萬次**：**無效竄改 1,174 次 ＝ 5.87%**（與 6.25% 理論值一致） |
| 修法 | 改竄**最後一段的首字元**——其 6 個位元**全部有效** → **保證**改到 byte 0 |
| ★ 修法之實證 | 同實驗 **2 萬次：無效竄改 0 次 ＝ 0.00%** |
| 修正後回歸 | 該測試**連跑 12 次全過**；全量測試亦通過 |

> ★★ **為何這是重要缺陷（不只「測試不穩」）**：6.25% 之隨機失敗會**訓練團隊忽略紅燈**
> ——CI 隨機紅 → 直覺按重跑 → 總有一天**真的壞了也被當成「又 flaky」**。
> 銀行案之 CI 必須**可信**；不穩的測試**比沒有測試更糟**。
> ★ **同型風險**：任何「以字串層級竄改 Base64」之測試，都要問「**這段有幾個 bit 是有效的？**」。

---

## 5. 已知限制（誠實揭露）

1. **本次只修後端 Jackson**——**前端 1 HIGH＋3 MODERATE**（`vite`／`react-router`）**未處理**。
2. **未做效能回歸**：Jackson 為序列化核心路徑，本次僅以「全量測試 ＋ 服務啟動」驗證，
   **未**量測序列化吞吐。
3. **`software.amazon.awssdk:third-party-jackson-core:2.55.9` 不在覆寫範圍**——
   那是 AWS SDK **自行重打包**之 Jackson（不同座標、非 Jackson BOM 管理）；
   本次掃描**未命中**，故不動（避免無依據地改）。
4. **BOM 覆寫僅作用於本 repo 之複合建置**——`CSP-002 §2` 拆分後各倉庫同源產生，故亦含同一段。
5. ★ **仍剩 1 筆 MODERATE：`at.yawk.lz4:lz4-java:1.10.1`**（修復版 **1.11.1**）——
   **不屬 Jackson**（係 Kafka 之壓縮相依），故**不在本 CR 範圍**。
   ⚠️ **未擅自更動**——Kafka 之相依鏈須另做相容性查證（另立任務）。
   **後端目前狀態：HIGH 0／CRITICAL 0／MODERATE 1。**

---

## 6. 修訂記錄

| 版本 | 日期 | 修訂內容 |
|---|---|---|
| 1.0 | 2026-10-05 | 初版：診斷 10 HIGH ＋ 5 MODERATE（2.x／3.x 兩線）；**查證 6 項**（★ 發現 BOM **import 兩個 Jackson BOM**）；裁定**匯入較新 BOM（機制 B）**而非逐個 constraint（★ 附判準）；訂定 6 項驗證要求並**全數通過**；四項已知限制 |
