Skip to content

Commit 65ef180

Browse files
authored
fix: prevent path traversal in LaTeX macro handlers (#3330)
* fix(latex): prevent path traversal in LaTeX macro handlers Signed-off-by: Cesar Berrospi Ramis <ceb@zurich.ibm.com> * style(latex): remove unnecessary imports and deprected typing.List Signed-off-by: Cesar Berrospi Ramis <ceb@zurich.ibm.com> --------- Signed-off-by: Cesar Berrospi Ramis <ceb@zurich.ibm.com>
1 parent 09de7f9 commit 65ef180

File tree

1 file changed

+28
-2
lines changed

1 file changed

+28
-2
lines changed

docling/backend/latex/handlers/macros.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import logging
22
import re
33
from pathlib import Path
4-
from typing import TYPE_CHECKING, Callable, List, Optional
4+
from typing import TYPE_CHECKING, Callable
55

66
if TYPE_CHECKING:
77
from io import BytesIO
@@ -162,7 +162,7 @@ def _process_macro_node_inline(
162162
parent: NodeItem | None,
163163
formatting: Formatting | None,
164164
text_label: DocItemLabel | None,
165-
text_buffer: List[str],
165+
text_buffer: list[str],
166166
flush_fn: Callable[[], None],
167167
following_nodes=None,
168168
) -> int:
@@ -307,7 +307,19 @@ def _process_macro( # noqa: C901
307307
image = None
308308
try:
309309
if isinstance(self.path_or_stream, Path):
310+
base_dir = self.path_or_stream.parent.resolve()
310311
img_full_path = self.path_or_stream.parent / img_path
312+
try:
313+
if not img_full_path.resolve().is_relative_to(base_dir):
314+
_log.warning(
315+
f"Path traversal attempt blocked for image: {img_path}"
316+
)
317+
raise ValueError("Path traversal not allowed")
318+
except ValueError:
319+
_log.warning(
320+
f"Invalid path for image (different drive or traversal): {img_path}"
321+
)
322+
raise
311323
if img_full_path.exists():
312324
suffix = img_full_path.suffix.lower()
313325
if suffix == ".pdf":
@@ -353,9 +365,23 @@ def _process_macro( # noqa: C901
353365

354366
filepath = self._extract_macro_arg(node)
355367
if filepath and isinstance(self.path_or_stream, Path):
368+
base_dir = self.path_or_stream.parent.resolve()
356369
input_path = self.path_or_stream.parent / filepath
357370
if not input_path.suffix:
358371
input_path = input_path.with_suffix(".tex")
372+
373+
try:
374+
if not input_path.resolve().is_relative_to(base_dir):
375+
_log.warning(
376+
f"Path traversal attempt blocked for input file: {filepath}"
377+
)
378+
return
379+
except ValueError:
380+
_log.warning(
381+
f"Invalid path for input file (different drive or traversal): {filepath}"
382+
)
383+
return
384+
359385
resolved = str(input_path.resolve())
360386
if resolved in self._input_stack:
361387
_log.warning(f"Circular \\input detected: {filepath}")

0 commit comments

Comments
 (0)