Cover image for CVE-2026-59924 Security Research

CVE-2026-59924

Path traversal in mistune's Include directive allows reading arbitrary files outside the intended markdown directory. Affects all versions up to 3.1.4, fixed in 3.3.0.

Summary

A path-traversal issue exists in mistune, a Python Markdown parser, in the optional Include directive used by its RST-style directive plugin. When a markdown file is processed with md.read(), a crafted include path can cause mistune to read files located outside the intended markdown directory. The issue affects all versions up to and including 3.1.4 and is fixed in 3.3.0.

Vulnerability Details

The Include directive lets one markdown file pull in the contents of another file by relative path. The flaw sits in Include.parse(), where the requested path is joined onto the current file’s directory and normalized, but the result is never checked to confirm it stays within that directory:

relpath = self.parse_title(m)
dest = os.path.join(os.path.dirname(source_file), relpath)
dest = os.path.normpath(dest)

Because dest is used to open a file without first verifying it is a descendant of a trusted base directory, a relative path containing enough ../ sequences can escape the markdown source tree entirely and reference arbitrary files elsewhere on the filesystem, limited only by the permissions of the running process.

  • Weakness class: Improper Limitation of a Pathname to a Restricted Directory (Path Traversal)
  • Attack vector: Network — reachable wherever untrusted markdown is rendered server-side
  • Attack complexity: High — requires the target application to render attacker-supplied markdown through the Include directive
  • Privileges required: None
  • User interaction: None

Impact

Applications that process untrusted or user-submitted markdown with the Include directive enabled may allow unintended file disclosure. The confidentiality impact is rated High: an attacker able to submit markdown that gets rendered by the vulnerable code path could read arbitrary files accessible to the process, such as configuration files, credentials, or source code outside the intended docs directory. There is no integrity or availability impact — the flaw only permits reading files, not modifying or deleting them.

Real-world exposure depends on whether an application:

  • Enables RSTDirective with the Include plugin, and
  • Renders markdown originating from a source it does not fully control (user uploads, wiki content, external contributions, etc.)

Proof of Concept — Steps to Reproduce

  1. Create a markdown file, e.g. test.md, containing an include directive that traverses upward out of its directory:
.. include:: ../../../example.txt
  1. Process the file with mistune’s RSTDirective and Include plugin enabled:
import mistune
from mistune.directives import RSTDirective, Include

md = mistune.create_markdown(
    plugins=[RSTDirective([Include()])]
)

result, state = md.read("test.md")
print(result)
  1. Observe that the contents of example.txt, located outside the markdown source directory, are read and included in the output — confirming the path traversal.

Affected Version and Fixed Version

Affected versionsmistune ≤ 3.1.4
Fixed versionmistune 3.3.0

CWE Classification

CWE-22 — Improper Limitation of a Pathname to a Restricted Directory (“Path Traversal”)

Remediation

  • Upgrade mistune to 3.3.0 or later, which validates that a resolved include path stays within the expected base directory before opening it.
  • If upgrading immediately isn’t possible, disable the Include directive for any pipeline that renders markdown from a source you do not fully trust — user uploads, external contributions, or content sourced from the internet.
  • After upgrading, audit any deployments that render user-supplied markdown to confirm no other custom directives introduce similar unrestricted file-path resolution.

Source: GitHub Security Advisory GHSA-r4rv-85jg-w4mf, lepture/mistune.