Docling 的 Tectonic TikZ 渲染可任意讀寫檔案
GitHub Advisory Database · 2026-10-07
Docling 的 LaTeX 後端只要改用 Tectonic 引擎渲染 TikZ 圖,惡意 .tex 就能讓處理程序讀走任何它讀得到的檔案,並在任何它寫得進去的路徑建立或覆寫檔案。這個問題登記為 CVE-2026-105744(GHSA-x3q2-h9hx-4r4j),嚴重度 high,CVSS v3 分數 7.5,在 docling 與 docling-slim 的 2.132.0 修補。
如果同時開了 shell escape,文件還能透過 \write18 直接執行指令。
漏洞機制
Docling 轉換 LaTeX 時,可以把文件裡的 TikZ 圖交給外部編譯器畫成圖片。docling/backend/latex/engines/tectonic.py 的做法是把圖的原始碼寫進暫存文件,再對它執行 tectonic 執行檔。其中的 _resolve_local_dependency 只決定哪些檔案要複製進暫存目錄,並不限制 TeX 編譯時實際會開啟什麼。
於是 TeX 本身的檔案原語全部可用:
\input{/abs/path}、\verbatiminput{...}、\openin可讀任意檔案,內容還能被排進圖裡,最後出現在轉換輸出中。\immediate\openout與\write可在暫存目錄之外建立或覆寫檔案,而且不需要 shell escape。- 輸入若是記憶體內的
DocumentStream,連暫存檔的 staging 步驟都會整個略過。
advisory 特別指出,Tectonic 的 --untrusted 旗標擋不住上述寫檔行為。所以「我有用 untrusted 模式」不能當成防護。
另有一個獨立的問題:TectonicEngine 建構子的 allow_shell_escape 預設是 True。Docling 的 LaTeX 後端一律明確傳入 tikz_engine_allow_shell_escape(預設 False),所以這個預設值只影響直接實例化 TectonicEngine 的程式。
受影響版本與條件
版本範圍是 >= 2.94.0, < 2.132.0,docling 與 docling-slim 兩個 pip 套件都在內。但要中招必須同時滿足下列三項:
- 呼叫端設定了
tikz_engine="tectonic"。 - 環境中找得到
tectonic執行檔(在PATH或 docling 快取裡)。 - 轉換的是不受信任的 LaTeX。
預設設定(tikz_engine=None)不受影響。Docling 不會自動安裝 tectonic,CLI 也沒有開啟它的選項。所以真正需要檢查的是:把 Docling 包進文件解析服務、接受使用者上傳 .tex,且程式碼裡自己開了 Tectonic 的人,例如 RAG 攝取管線與論文轉 Markdown 的服務。
advisory 給的 PoC 只有幾行,用 \openout 在 TikZ 圖裡寫檔:
\begin{tikzpicture}
\immediate\openout15=/tmp/docling-tectonic-poc.txt
\immediate\write15{written by the input document}
\immediate\closeout15
\node {x};
\end{tikzpicture}以 LatexBackendOptions(tikz_engine="tectonic") 轉換這份文件,就會在 /tmp/docling-tectonic-poc.txt 產生檔案。advisory 也提醒,寫入啟動檔或設定檔可進一步導致程式碼執行,所以歸類在 RCE 風險之下並不誇張。
修補與緩解
修補由 PR #4419 帶入,包含在 v2.132.0,做了兩件事:
| 項目 | 2.132.0 之前 | 2.132.0 |
|---|---|---|
TectonicEngine 的 allow_shell_escape 預設 | True | False |
| 未開 shell escape 時的 Tectonic 參數 | 無額外限制 | --untrusted 與 --only-cached |
| 編譯前檢查 | 無 | 掃描產生的文件與每個 staged 檔案 |
新增的檢查會在原始碼用到 \openin、\openout、\XeTeXpicfile、\XeTeXpdffile,或在 \input、\include、\includegraphics、\InputIfFileExists、\graphicspath 中使用絕對路徑、家目錄、磁碟代號或上層目錄時,跳過渲染並把圖保留為 TikZ 原始碼。
這個檢查只是 best-effort。它讀的是原始碼文字,而 TeX 可以透過套件指令或巨集拼出來的檔名開檔,文字比對看不到。advisory 因此仍然要求:以 tikz_engine="tectonic" 渲染不受信任的 LaTeX 時,必須放進隔離環境。
無法立刻升級的人,advisory 列出的 workaround 是:
- 不要對不受信任的輸入啟用
tikz_engine="tectonic",或改在 OS 層沙箱中轉換:容器、不掛載主機目錄、唯讀檔案系統、無網路。 - 對不受信任的輸入,絕不設定
tikz_engine_allow_shell_escape=True。
實務上先用 pip show docling 確認版本是否落在範圍內,再在程式碼裡搜尋 tikz_engine。沒有出現就不受影響。有出現的話,升級到 2.132.0,並確認轉換行程以最小權限執行,因為這類洩漏與覆寫的上限,就是該行程本身的檔案權限。
CWE 分類:CWE-22、CWE-73、CWE-1188(不安全的資源初始預設值)。commit 見 38b6fa0。