Skip to content

fix: security issues - #89

Merged
dfop02 merged 2 commits into
release/1.3.0from
patch/fix-security-issues
Nov 9, 2026
Merged

dfop02 merged 2 commits into
release/1.3.0from
patch/fix-security-issues

Conversation

@dfop02

@dfop02 dfop02 commented Nov 9, 2026 •

Copy link
Copy Markdown
Owner

Summary

Fixes SSRF (CWE-918) and arbitrary local file read (CWE-73 / CWE-22) when converting untrusted HTML to DOCX. All versions up to and including 1.2.1 are affected.

Before this change, every <img src> and <link rel="stylesheet" href> was fetched with urllib.request.urlopen or open() with no restrictions, so attacker-controlled HTML could make the server request internal services and cloud metadata endpoints (e.g. 169.254.169.254) or read arbitrary local files. Image responses were embedded into the generated .docx, exfiltrating their content.

Advisory: GHSA-xh3w-67hm-58x9

What changed

Security

  • Resource fetching moved to a new html4docx/resources.py module, governed by a ResourcePolicy built from parser.options.
  • Remote fetches are restricted to http/https. The opener only registers HTTP(S) handlers, so file://, ftp:// and other schemes are refused, including through redirects.
  • Connections to non-public IPs (loopback, private, link-local/cloud metadata, reserved, multicast) are refused. The check runs on the IP actually connected to, on every redirect hop, which also prevents DNS rebinding.
  • Local files are disabled by default and, when enabled, confined to local-files-root (.. and symlinks resolved first).
  • Each resource is capped at max-resource-bytes (10 MB by default).
  • HTTP_PROXY / HTTPS_PROXY are ignored, since routing through a proxy would bypass the private network check (and avoids httpoxy).

New options

Option Default Description
allow-remote-resources True Fetch http/https images and stylesheets.
private-network-allowlist [] Private IPs/CIDRs that may be fetched. Invalid entries raise ValueError.
allow-private-network False Allow every non-public address (trusted HTML only). Takes precedence over the allowlist, and a warning is logged if both are set.
local-files-root None Directory local files may be read from. None disables local files.
max-resource-bytes 10485760 Maximum size of each fetched resource.

Tests and CI

  • New tests/test_security.py covering SSRF via <img> and <link>, private/metadata IPs, redirects to private addresses, blocked schemes, size limit, local file confinement and path traversal, the allowlist, option precedence and the combined-options warning.
  • Existing tests that use local assets now set local-files-root.
  • pytest-xdist added to speed up the test suite on CI.
  • Python 3.15 added to the CI matrix.

Docs

  • README: options reorganized, new "External resources security" and "Migrating from <=1.2.x" sections, and outdated examples fixed.
  • HISTORY: 1.3.0 entry.

⚠️ Breaking changes

  • Local files (paths and file://) are disabled by default. Set parser.options['local-files-root']; relative paths are now resolved against it instead of the current working directory.
  • Private network addresses (e.g. intranet servers) are blocked by default. Add them to private-network-allowlist.
  • HTTP_PROXY / HTTPS_PROXY are no longer honored when fetching remote resources.

Public http/https URLs and data:image/... images work as before.

Issue Reference

None

Checklist Before Requesting a Review

  • I have performed a self-review of my code.
  • My code follows the project's coding style and guidelines.
  • I have run tests and verified that all existing and new tests pass.
  • I have added new tests to cover my changes.

@dfop02 dfop02 self-assigned this Nov 9, 2026
@dfop02 dfop02 added documentation Improvements or additions to documentation New Feature New feature or request Security Address security fixes labels Nov 9, 2026
@dfop02
dfop02 merged commit be7b88c into release/1.3.0 Nov 9, 2026
6 checks passed
@dfop02
dfop02 deleted the patch/fix-security-issues branch November 9, 2026 17:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation New Feature New feature or request Security Address security fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant