FlawOpen

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

● CVE-2026-105750 · CVSS 5.9 · Medium
FlawOpen Security Research

CVE-2026-105750: Docling HTML Render Local File Disclosure

Docling versions before 2.118.1 can disclose local text files when Python code renders untrusted HTML from a filesystem Path with render_page=True and Playwright installed. The HTML browser path failed to enforce enable_local_fetch and directory confinement. Upgrade to 2.118.1 or later.

💡 Plain English Explainer (ELI5)

A document converter is like a clerk who photographs a page in a browser. A setting said “do not fetch local files,” but one browser-rendering path waved local-file requests through anyway. If the submitted page could make that browser display a file the converter could read, the file’s visible text could end up in the returned document image. The fix checks the setting and keeps allowed local files inside the source document’s directory.

Core Concepts & Subsystem Terms

Docling HTML backend
The Docling component that parses HTML and can optionally render the page in a headless browser to capture its visual layout.
HTMLBackendOptions(render_page=True)
A Python-only option that enables the headless-browser rendering path. It is off by default.
enable_local_fetch
A policy option that controls whether local files may be fetched as document resources. A backend must enforce it for every resource request.
Playwright
The optional browser automation dependency used by Docling’s HTML page-rendering mode.
Path input
A filesystem path used as the source document. Unlike stream input, it gives the browser-rendering flow a file URL origin.
CWE-863
Incorrect Authorization: the render-mode request filter failed to enforce the configured local-file access policy.

Framework mappings

  • CWE reference for the weakness described in this guide: CWE-863

Root Cause Analysis

In affected render-mode versions, HTMLDocumentBackend._get_browser_request_block_reason() treated file: URLs as allowed before it checked enable_local_fetch or confined the resolved path to the source document’s directory. For Docling 2.82.0–2.90.x, the advisory says render mode did not filter requests at all. The vulnerable boundary is the browser resource-request policy, not general HTML parsing or every Docling deployment. The GitHub advisory classifies CWE-863 and also lists CWE-552 for the disclosure impact; this page uses CWE-863 as the primary root-cause mapping.

Step-by-Step Attack Flow

Step 1

An application enables optional HTML rendering

The vulnerable deployment uses the Python API with HTMLBackendOptions(render_page=True) and has Playwright installed. The default configuration, Docling CLI, and docling-serve are outside the advisory’s affected configuration.

Step 2

The application submits HTML as a filesystem Path

The advisory limits the affected input to untrusted HTML passed as a Path. Stream inputs use page.set_content() with an opaque origin and are not affected by this file-subresource path.

Step 3

The headless browser requests a local resource

HTML can cause browser-rendered subresources to be requested. The affected request callback allowed file: requests without enforcing the configured local-fetch permission; even with local fetch enabled, it lacked the source-directory confinement used by the non-render path.

Step 4

Readable text can appear in the rendered image

The disclosed impact is limited to text a local file exposes visibly inside the browser viewport. JavaScript is disabled in the browser from Docling 2.91.0; do not generalize this issue to arbitrary code execution or invisible bytes.

Step 5

The fixed filter restores both policy checks

Docling 2.118.1 allows the source document itself, blocks other file requests unless enable_local_fetch is true, and confines allowed file subresources to the source document’s directory.

Source Code: Flaw vs. Secure Implementation

The vulnerable excerpt shows the unconditional file: allow rule documented by the maintainer advisory; it is not a complete source file. The fixed excerpt follows upstream commit 1612b88: allow the source HTML file to load, require enable_local_fetch for other local files, resolve the requested path, and enforce source-directory containment. Upgrade to 2.118.1 or later rather than copying this focused excerpt. The separate data:, about:, and blob: handling remains outside the local-file rule.

Source excerpt: docling/backend/html_backend.py — focused excerpts from the affected and fixed request policy

UNPATCHED FLAW
# Affected render path: file: was allow-listed before local-fetch policy checks.
if scheme in {"file", "data", "about", "blob"}:
    return None
HARDENED SECURE PATCH
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)

# In _get_browser_request_block_reason():
if scheme == "file":
    if self._is_allowed_browser_file_request(request_url):
        return None
    # Otherwise return a reason that the request is blocked.

Engineering & System Hardening Checklist

Sources