VAITP Dataset

← Back to the dataset

CVE-2025-46656

markdownify < 0.14.1 allows large headline prefixes, causing memory consumption.

  • CVSS 3.3
  • CWE-1284
  • Resource Management
  • Remote

python-markdownify (aka markdownify) before 0.14.1 allows large headline prefixes such as <h9999999> in addition to <h1> through <h6>. This causes memory consumption.

CVSS base score
3.3
Published
2025-04-26
OWASP
A08 Software and Data Integrity Failures
Orthogonal defect classification
Algorithm
Code defect classification
Incorrect Functionality
Category
Resource Management
Subcategory
Resource Management
Accessibility scope
Remote
Impact
Denial of Service (DoS)
Affected component
python-markd
Fixed by upgrading
Yes

Solution

Upgrade to version 0.14.1 or later.

Vulnerable code sample

import markdownify
import time

def demonstrate_cve_2025_46656(prefix_length):
    """
    Demonstrates potential memory consumption issue with large headline prefixes
    in markdownify before version 0.14.1.  This is a simplified simulation
    as the exact internal workings of the vulnerable code are not fully known.

    Args:
        prefix_length: The number of '9's to use in the <h> tag prefix.
    """

    html_input = f"<h{ '9' * prefix_length }>This is a large headline</h{ '9' * prefix_length }>"

    start_time = time.time()
    try:
        markdown_output = markdownify.markdownify(html_input)  # Simulate pre-0.14.1 behavior
        print(f"Markdown output: {markdown_output}")
    except Exception as e:
        print(f"Error during conversion: {e}")

    end_time = time.time()
    print(f"Conversion took {end_time - start_time:.4f} seconds")

if __name__ == "__main__":
    # Test with increasing prefix lengths to observe potential slowdown
    # and (if memory is limited) potential memory errors.  Adjust the range
    # depending on your system resources.

    for prefix_length in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]: # increase this range at your own risk
        print(f"\nTesting with prefix length: {prefix_length}")
        demonstrate_cve_2025_46656(prefix_length)

Patched code sample

import re

def markdownify(html):
    """
    Converts HTML to Markdown, mitigating CVE-2025-46656.
    """

    def replace_headline(match):
        level = int(match.group(1))
        if 1 <= level <= 6:  # Limit heading levels to 1-6
            return "#" * level + " " + match.group(2) + "\n"
        else:
            return match.group(2) + "\n" # Treat as regular text if invalid level

    # Use a regular expression to find all headlines.  The r'\d+' pattern is crucial
    # for extracting the heading level while avoiding excessive memory consumption from large levels.
    html = re.sub(r'<h(\d+)>(.*?)</h\1>', replace_headline, html, flags=re.IGNORECASE)

    # Basic text processing (replace with more comprehensive logic as needed)
    html = html.replace('<p>', '').replace('</p>', '\n')
    html = html.replace('<b>', '**').replace('</b>', '**')
    html = html.replace('<i>', '*').replace('</i>', '*')

    return html

if __name__ == '__main__':
    # Example Usage:  This is where the vulnerability would be triggered in older versions.
    html_input = "<h9999999>This is a very large heading!</h9999999><p>Some text.</p>"
    markdown_output = markdownify(html_input)
    print(markdown_output)

    html_input2 = "<h1>Normal heading</h1>"
    markdown_output2 = markdownify(html_input2)
    print(markdown_output2)

    html_input3 = "<h7>Invalid heading</h7>"
    markdown_output3 = markdownify(html_input3)
    print(markdown_output3)

Payload

<h9999999>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</h9999999>

Cite this entry

@misc{vaitp:cve202546656,
  title        = {{markdownify < 0.14.1 allows large headline prefixes, causing memory consumption.
}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2025},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2025-46656},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2025-46656/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.

The supreme art of war is to subdue the enemy without fighting.

Sun Tzu – “The Art of War”

:: Shaping the future through research and ingenuity ::