資安雷達 2026 年 10 月 6 日

2026-10-06 — Tinypool 2.1.1 修補 worker 選項原型污染,可致 RCE

primary=https://github.com/advisories/GHSA-5gmw-xhrv-c9v3 primary=https://github.com/tinylibs/tinypool/pull/134 primary=https://github.com/tinylibs/tinypool/releases/tag/v2.1.1

Tinypool 2.1.1 修補 worker 選項原型污染,可致 RCE

GitHub Advisory Database · 2026-10-05

Tinypool 把 worker 選項從一個繼承 Object.prototype 的普通物件上直接讀出來,只要任何地方污染了原型,攻擊者設定的 execArgv 與 env 就會原封不動傳給 new Worker()。這個缺陷編號 CVE-2026-104848(GHSA-5gmw-xhrv-c9v3),CVSS v4 為 9.5(Critical),影響 npm 套件 tinypool ≤ 2.1.0,2.1.1 已修補。

原本的問題

JavaScript 的普通物件讀取屬性時,找不到自有屬性就會沿著原型鏈往上找。只要程式把「沒設定」當成預設值,就等於信任了 Object.prototype。Tinypool 對 env、argv、execArgv、resourceLimits 這四個傳給 Worker 的選項都是這種寫法,而其中 execArgv 與 env 恰好能控制 Node.js 啟動時載入什麼程式。

這也是為什麼 --require 這類旗標會成為利用手段:Node.js 在 worker 啟動階段就會先載入指定檔案,早於任何應用程式碼。攻擊者不需要碰到 tinypool 的 API,只需要在同一個行程裡的任何依賴中找到一個能寫入 Object.prototype 的缺陷。

時間線

  • 2026-08-23:PR #134 合併進主分支。
  • 2026-08-30:GitHub 公告發布。
  • 2026-10-02:NVD 收錄 CVE-2026-104848。
  • 2026-10-05:公告資料庫更新。回報者為 ambushneupane。

修補在 8 月底就已存在,所以多數靠 Dependabot 或定期更新的專案可能已經升過;真正還暴露的是鎖死舊版 lockfile、或長期不更新測試工具鏈的 repo。

漏洞機制

原型污染本身通常只是「改掉別人沒設定的預設值」,要升級成 RCE 需要一個會讀取未設定屬性的 gadget。Tinypool 就是這個 gadget:公告指出它「passes worker options to new Worker() by reading them off a plain object whose prototype is Object.prototype」。

具體位置在 dist/index.js 第 508 至 511 行,公告列出的讀取方式如下:

env:            this.options.env,
argv:           this.options.argv,
execArgv:       this.options.execArgv,
resourceLimits: this.options.resourceLimits,

選項物件在第 470 行以 spread 語法建立,繼承來的屬性會被展開成自有屬性,所以就算使用者從未傳入 execArgv,被污染的值也會被當成合法設定。

公告列出兩條利用路徑:

  • execArgv 污染:設定 Object.prototype.execArgv = ['--require', '/path/to/attacker.js'],所有 pool worker 啟動時都會載入攻擊者的檔案。
  • env 污染:設定 Object.prototype.env = { NODE_OPTIONS: '--require /path/to/attacker.js' },透過環境變數注入達成同樣效果。

結果是「arbitrary code execution inside every worker the pool spawns, with the privileges of the host process」。

受影響版本

項目內容
受影響tinypool ≤ 2.1.0
已修補2.1.1
嚴重度CVSS v4 9.5,Critical
EPSS0.497%(第 40 百分位)

公告提到 tinypool 是 Vitest 的底層依賴,Vitest 每週下載量約 4200 萬次,所以風險落在開發者機器與 CI/CD:被污染的測試依賴或測試輸入,可能讓攻擊者取得建置產物與機密。要注意的是,這個漏洞需要先有一個能污染原型的入口,單靠 tinypool 本身無法觸發;它的作用是把原本「只能改行為」的污染升級為程式碼執行。

影響範圍

公告強調的是 worker 的權限:注入的程式碼以宿主行程的權限執行,而不是被沙箱隔離的子環境。對開發者機器來說,這代表可讀取家目錄裡的 SSH 金鑰與 token;對 CI 來說,則是可讀取環境變數中的發佈憑證,甚至改動建置產物。

需要特別檢查的對象有三類:直接依賴 tinypool 的函式庫作者、使用 Vitest 的專案(透過間接依賴帶入)、以及會對外部貢獻者的 PR 自動跑測試的 CI 流程。第三類最危險,因為外部提交的測試碼本身就可能成為污染原型的入口。

修補與緩解

修補提交為 24df4e7,對應 PR #134「fix: guard worker options from proto pollution」。公告建議的方向是改用自有屬性語意,讓選項物件沒有原型:

// 舊:選項物件繼承 Object.prototype
this.options = { ...kDefaultOptions, ...options, filename, maxQueue: 0 }
// 公告建議
this.options = Object.assign(Object.create(null),
  kDefaultOptions, options, { filename, maxQueue: 0 });

上面「舊」的寫法是依公告對第 470 行 spread 的描述改寫,並非原始碼逐字引用;實際合併的 diff 公告頁與 PR 頁都沒有完整列出,細節以 PR 為準。

實務上該做的事:

  • 用 npm ls tinypool 或 lockfile 檢查是否有 ≤ 2.1.0,包含 Vitest 帶進來的間接依賴,升到 2.1.1。
  • CI 若會執行不受信任的 PR 或第三方測試碼,在升級前不要給它存取機密。
  • 公告未提供不升級的緩解方式,這部分「公告未說明」。

原始來源:GitHub Advisory GHSA-5gmw-xhrv-c9v3、tinypool PR #134、tinypool v2.1.1


End of article
0
Would love your thoughts, please comment.x
()
x