docling-project/docling · critical · SecurityError
ZIP slip attempt: {member.filename}
Error message
ZIP slip attempt: {member.filename} What it means
When downloading EasyOCR model archives, docling extracts each zip member after checking that the resolved destination stays inside the target directory. If a member filename like '../../etc/passwd' would escape local_dir, a SecurityError is raised naming the offending entry. This is a defense against the ZIP slip path-traversal attack, and it means the downloaded archive is malformed or was tampered with, not that your code is wrong.
Source
Thrown at docling/models/stages/ocr/easyocr_model.py:181
recognition_models_by_name = {
model_name: model_details
for generation in rec_models_dict.values()
for model_name, model_details in generation.items()
}
for model_name in recognition_models:
if model_name in recognition_models_by_name:
download_list.append(recognition_models_by_name[model_name])
# Download models
for model_details in download_list:
buf = download_url_with_progress(model_details["url"], progress=progress)
with zipfile.ZipFile(buf, "r") as zip_ref:
for member in zip_ref.infolist():
member_path = os.path.realpath(
os.path.join(local_dir, member.filename)
)
if not member_path.startswith(os.path.realpath(local_dir) + os.sep):
raise SecurityError(f"ZIP slip attempt: {member.filename}")
zip_ref.extract(member, local_dir)
return local_dir
def __call__(
self, conv_res: ConversionResult, page_batch: Iterable[Page]
) -> Iterable[Page]:
if not self.enabled:
yield from page_batch
return
for page in page_batch:
assert page._backend is not None
if not page._backend.is_valid():
yield page
else:
with TimeRecorder(conv_res, "ocr"):
ocr_rects = self.get_ocr_rects(page)View on GitHub (pinned to 61d76f1ff3)
Solutions
- Delete the partially downloaded cache/artifacts and retry the model download from the official source on a trusted network.
- Verify the download URL and integrity of the model archive (hash) if your setup pins URLs.
- If it recurs, fetch models manually from the EasyOCR upstream repository and place them in artifacts_path, and report the incident — a zip-slip hit can indicate tampering.
Defensive patterns
Strategy: try-catch
Validate before calling
def zip_is_safe(zip_path: Path, dest: Path) -> bool:
dest_real = os.path.realpath(dest)
with zipfile.ZipFile(zip_path) as zf:
return all(
os.path.realpath(os.path.join(dest_real, m.filename)).startswith(dest_real + os.sep)
for m in zf.infolist()
) Try / catch
try:
model_dir = model.download_models(local_dir=artifacts)
except SecurityError as err:
logger.critical("Model archive failed ZIP-slip check: %s — possible tampering", err)
raise # do NOT bypass; retry from a trusted network/source instead Prevention
- Treat any zip-slip hit as a security incident: verify the download source and archive hashes before retrying.
- Pin model download URLs to official hosts; avoid untrusted mirrors/proxies for model artifacts.
- Keep the artifacts cache cleanable so a re-download is a cheap recovery path.
When it happens
Trigger: Prefetching/downloading EasyOCR models (download_models) where the fetched zip contains entries whose paths resolve outside the extraction directory — malicious or corrupted archive, or a redirected/spoofed download URL.
Common situations: Compromised or misconfigured model host serving crafted archives; corporate proxies returning HTML/error pages saved as zips with odd entry names; corrupted downloads from interrupted transfers.
Related errors
- ZIP slip attempt: {info.filename}
- Path traversal blocked: '{loc}' resolves outside base direct
- Resource bundle contains an unsafe path: {member!r}
- Resource bundle references an image outside the bundle: {uri
- easyocr_languages requires with_easyocr=True
AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14).
Data as JSON: /api/errors/a348768db90aa28f.
Report an issue: GitHub.