s2n-quic 加密握手緩衝區未設上限,單一封包可誘發近 10MB 記憶體配置
github.com · 2026-08-14
AWS 的 Rust QUIC 實作 s2n-quic(aws/s2n-quic,IETF QUIC 協定的開源實作,約 1,300+ stars)在 1.81.0 及更早版本中,握手階段的 CRYPTO 幀重組緩衝區沒有大小上限。未經驗證的攻擊者只要送出一個帶有超大 offset 的 CRYPTO 幀,就能讓伺服器在完成 TLS 握手前配置大量記憶體,官方描述單一 1200 bytes 封包即可觸發約 9.4MB 配置。此漏洞編號為 GHSA-9q54-f358-3fqf(CVE-2026-10740),CVSS 6.9(中度),已在 1.82.0 修補。
漏洞機制
QUIC 握手訊息(ClientHello、憑證鏈等)透過 CRYPTO 幀傳輸,幀本身帶有 offset 欄位,允許亂序抵達後由接收端重組。s2n-quic 的 CryptoStream::on_crypto_frame(quic/s2n-quic-transport/src/space/crypto_stream.rs)在寫入重組緩衝區前,程式碼原本只留了一行 //TODO we need to limit the buffer size here,對應的 RFC 9000 §7.5 規範(至少緩衝 4096 bytes、可自行選擇上限)從未真正實作。
意味著 offset 可以是任意大值,重組器(Reassembler)會依 offset 直接配置對應大小的底層儲存空間,而不論這段資料是否真的會被用到。攻擊者甚至不需要完成合法的握手,只要維持連線在早期階段反覆送出高 offset 的 CRYPTO 幀即可持續消耗伺服器記憶體,構成不需驗證的阻斷服務攻擊(CWE-770)。
受影響版本
- cargo 套件
s2n-quic:≤ 1.81.0皆受影響 - 修補版本:
1.82.0 - 影響面:任何以 s2n-quic 作為伺服器端 QUIC/HTTP-3 實作的服務,無須攻擊者持有有效憑證或完成握手
修補與緩解
修補提交(6c90fa9)為 CryptoStream 新增常數 MAX_CRYPTO_BUFFER_SIZE = 128 * 1024,在寫入前先計算「目前 offset 加上資料長度」與「已消費長度」之間的距離,超過上限就直接以 CRYPTO_BUFFER_EXCEEDED錯誤關閉連線,而不是無條件配置緩衝區:
let end_offset = frame.offset.checked_add_usize(frame.data.len())
.ok_or(transport::Error::CRYPTO_BUFFER_EXCEEDED)?;
let buffered = end_offset.as_u64().saturating_sub(self.rx.consumed_len());
if buffered > MAX_CRYPTO_BUFFER_SIZE {
return Err(transport::Error::CRYPTO_BUFFER_EXCEEDED);
}
self.rx.write_at(frame.offset, frame.data)...128KiB 的上限刻意高於 RFC 要求的 4096 bytes 下限,是為了容納較大的憑證鏈等握手資料,同時仍能限制惡意 offset 造成的記憶體膨脹。使用 s2n-quic 作為伺服器的專案應升級至 1.82.0 或以上,無法立即升級者應在前端限制單一連線在握手完成前的資源配額。
Token Optimizer MCP:session 記錄 API 路徑穿越與 smart_user 指令注入,同一次修補一併處理
github.com · 2026-08-14
Token Optimizer MCP(npm 套件 @ooples/token-optimizer-mcp,官方描述為「量測各 AI coding agent 的 token 節省量、優化 context,並在 16 種 CLI 客戶端間共享本地知識圖譜」的 MCP 伺服器)在 5.1.0 之前的版本存在兩個各自獨立、但由同一個修補提交解決的漏洞:dashboard API 的路徑穿越(GHSA-76pc-mqxp-3rq5,CVE-2026-55156,CVSS 5.3)與 smart_user 工具的作業系統指令注入(GHSA-49mq-fc6q-3h46,CVE-2026-55157,CVSS 8.4)。兩者都在 2026-08-14 由 GitHub 完成審核並公開。
漏洞機制:路徑穿越
該套件內建一個 dashboard web server(src/server/web-server.ts),/api/session-summary 與 /api/session-events 兩個端點不需要任何身分驗證,直接把 query string 帶入的 sessionId 用 path.join 接上 session-log-${sessionId}.jsonl 去讀檔。由於沒有格式檢查,攻擊者送入類似 abc/../../../../etc/passwd 的字串就能跳出 hooks 資料目錄,讀到任意 .jsonl甚至系統檔案,外洩內容包含工具呼叫紀錄、hook 輸出與 token 使用量等 session 資料。
漏洞機制:指令注入
smart_user 工具的 get-user-info 操作,Unix 分支下原本執行 getent passwd "${username}" || grep "^${username}:" /etc/passwd,用雙引號包住 username 直接串進 shell 指令字串再交給 child_process.exec。雙引號無法阻擋 shell 的指令替換語法,只要 username 帶有 $(...) 或反引號,被包起來的內容一樣會先被 shell 展開執行,等同任意指令注入,且以 MCP 伺服器行程的權限執行。
受影響版本與修補
| GHSA | 類型 | CVSS | 受影響版本 | 修補版本 |
|---|---|---|---|---|
GHSA-76pc-mqxp-3rq5 | 路徑穿越 (CWE-22) | 5.3 | < 5.1.0 | 5.1.0 |
GHSA-49mq-fc6q-3h46 | OS 指令注入 (CWE-78) | 8.4 | < 5.1.0 | 5.1.0 |
兩個漏洞都在同一個修補提交 b4ee96d 中處理,該提交同時也修掉了同一批 smart_* 工具(smart_diff、smart_branch、smart_install 等)中類似的 shell 字串拼接問題。smart_user 改為透過新增的 src/utils/safe-exec.ts,以 argv 陣列模式呼叫 execFile(不經過 shell),使用者輸入不再有機會被 shell 解析:
// 修補前
const { stdout } = await execAsync(
`getent passwd "${'${username}'}" || grep "^${'${username}'}:" /etc/passwd`
);
// 修補後
assertSafeArg(username, 'username');
const { stdout } = await execFileSafe('getent', ['passwd', username]);
// getent 查無結果時,改為在程式內掃描 /etc/passwd 字串比對,
// 不再落回任何 shell pipelinedashboard 端點的修法則是新增 isValidSessionId,用嚴格的白名單正則 ^[A-Za-z0-9_-]{1,64}$ 擋掉任何 . 或路徑分隔字元,並加上 resolveSessionLogPath 進行 路徑歸屬驗證:對解析後的路徑做 path.relative,只要結果以 .. 開頭或是絕對路徑,一律視為越界並回傳 400。同一次提交還加上了 express-rate-limit(每分鐘 300 次請求)作為縱深防禦。
修補與緩解
- 升級
@ooples/token-optimizer-mcp至5.1.0或以上 - 升級前應避免將 dashboard web server 對外網或不受信任網路開放,兩個端點原生不需驗證
- 若自行維運 MCP server 且無法立即升級,可在反向代理層過濾
sessionId中的.、/與 shell 特殊字元作為暫時緩解