FlawOpen

flawopen.com/Teardowns/cve-2026-105750-docling-html-render-local-file-disclosure

● CVE-2026-105750 · CVSS 5.9 · 中
セキュリティ研究 · FlawOpen

CVE-2026-105750:Docling の HTML レンダリングによるローカルファイル漏えい

2.118.1 より前の Docling は、Python コードが Playwright をインストールした状態で render_page=True を使い、filesystem Path から信頼できない HTML を描画すると、ローカルテキストファイルを漏えいする可能性があります。ブラウザ経由では enable_local_fetch が適用されず、アクセスも文書ディレクトリ内に制限されていませんでした。2.118.1 以降へ更新してください。

💡 わかりやすい解説 (ELI5)

文書変換ツールを、ブラウザで開いたページを撮影する担当者だと考えてください。「ローカルファイルを取得しない」という設定があっても、描画経路の一つがその要求を通していました。送信されたページによってブラウザが変換プロセスから読めるファイルを表示すると、その見える文字が返却文書の画像に含まれる可能性があります。修正では設定を確認し、許可するローカルファイルを元文書のディレクトリ内に限定します。

主要な概念と専門用語

Docling HTML backend
HTML を処理し、必要に応じてヘッドレスブラウザでページを描画して視覚的なレイアウトを取得する Docling コンポーネント。
HTMLBackendOptions(render_page=True)
ブラウザ描画経路を有効にする Python API オプション。既定では無効です。
enable_local_fetch
ローカルファイルを文書リソースとして取得できるかを制御するポリシー設定。各 backend はすべてのリソース要求に適用する必要があります。
Playwright
Docling の HTML ページ描画で使われる任意のブラウザ自動化依存関係。
Path input
ファイルシステムのパスとして渡す入力ファイル。stream 入力と異なり、ブラウザ描画経路に file URL のオリジンを与えます。
CWE-863
Incorrect Authorization:描画モードの要求フィルターが、設定済みのローカルファイルアクセス方針を適用しませんでした。

フレームワーク対応

  • このガイドで説明する弱点の CWE 参照: CWE-863

根本原因の分析 (Root Cause)

影響を受ける描画モードのバージョンでは、HTMLDocumentBackend._get_browser_request_block_reason() が enable_local_fetch を確認したり、解決済みパスを元文書のディレクトリに制限したりする前に file: URL を許可していました。Docling 2.82.0–2.90.x では描画モードに要求フィルター自体がなかったとアドバイザリに記載されています。脆弱な境界はブラウザのリソース要求ポリシーであり、HTML の一般的な解析やすべての Docling 導入ではありません。GitHub アドバイザリは原因を CWE-863 に分類し、漏えいの影響に CWE-552 も挙げています。本記事では原因の主分類に CWE-863 を使用します。

ステップ・バイ・ステップの攻撃フロー

ステップ 1

アプリが任意の HTML 描画を有効にする

影響を受ける構成は Python API で HTMLBackendOptions(render_page=True) を使い、Playwright をインストールしています。アドバイザリでは既定設定、Docling CLI、docling-serve は対象外です。

ステップ 2

アプリが HTML を filesystem Path として渡す

アドバイザリは影響対象を Path として渡された信頼できない HTML に限定しています。stream 入力は page.set_content() と不透明なオリジンを使うため、この file サブリソース経路の影響を受けません。

ステップ 3

ヘッドレスブラウザがローカルリソースを要求する

HTML は描画中にサブリソース要求を発生させることがあります。影響を受けるコールバックはローカルアクセス許可を適用せず file: を許し、設定を有効にしても非描画経路のように元文書ディレクトリへ制限しませんでした。

ステップ 4

読める文字が描画画像に現れる可能性がある

公表された影響は、ローカルファイルがブラウザの表示領域に見せるテキストに限られます。Docling 2.91.0 以降はブラウザで JavaScript が無効です。任意コード実行や不可視バイトの読み取りと一般化しないでください。

ステップ 5

修正済みフィルターが両方の確認を戻す

Docling 2.118.1 は元文書自体の読み込みを許可し、enable_local_fetch が有効でなければ他の file 要求を拒否し、許可されたローカルサブリソースを文書ディレクトリ内に制限します。

ソースコード比較:脆弱 vs 堅牢化

脆弱な抜粋は、メンテナーのアドバイザリが説明する file: の無条件許可を示します。完全なソースファイルではありません。修正版の抜粋は upstream commit 1612b88 に基づき、元 HTML を許可し、他のローカルファイルには enable_local_fetch を要求し、要求パスを解決して文書ディレクトリ内に制限します。この抜粋をコピーするのではなく 2.118.1 以降へ更新してください。data:、about:、blob: の個別処理はローカルファイルの規則には含まれません。

ソース抜粋: docling/backend/html_backend.py — 要求と描画ポリシーの抜粋

脆弱な実装
# 影響を受けるレンダリング経路: file: はローカル取得ポリシーの確認前に許可されていた。
if scheme in {"file", "data", "about", "blob"}:
    return None
堅牢化されたセキュアパッチ
def _is_allowed_browser_file_request(self, request_url: str) -> bool:
    local_base_path = self._get_browser_local_base_path()
    if local_base_path is not None and request_url == local_base_path.as_uri():
        return True  # The source document itself must remain loadable.

    if not self.options.enable_local_fetch or local_base_path is None:
        return False

    requested_path = Path(url2pathname(urlparse(request_url).path)).resolve()
    return requested_path.is_relative_to(local_base_path.parent)

# _get_browser_request_block_reason() 内:
if scheme == "file":
    if self._is_allowed_browser_file_request(request_url):
        return None
    # それ以外の場合は、リクエストをブロックした理由を返す。

エンジニアリング&システム堅牢化チェックリスト

参考資料