FlawOpen

flawopen.com/Teardowns/cve-2026-104286-fortimail-ibe-path-traversal

● CVE-2026-104286 · CVSS 9.8[7] · Critical
FlawOpen Security Research

CVE-2026-104286: FortiMail IBE Path Traversal

CVE-2026-104286 lets unauthenticated HTTP(S) requests write files on vulnerable FortiMail systems through path traversal. Fortinet reports in-the-wild exploitation; disable IBE or restrict web access, investigate for compromise, and install the correct fixed release.[1], [5]

💡 Plain English Explainer (ELI5)

A mail gateway is like a locked mailroom with a clerk who files attachments. The flaw lets a request give the clerk a misleading folder path, so a file can be written outside the intended drop-off area. Fortinet's workaround closes the affected IBE door or limits who can reach the web interface while administrators patch and check whether anyone already got in.[1], [5]

Core Concepts & Subsystem Terms

Path traversal (CWE-22)
Untrusted path components escape the directory intended for a file operation. Fortinet describes unauthenticated arbitrary file writes on affected FortiMail systems.[1], [6]
Identity-Based Encryption (IBE)
FortiMail functionality for encrypted-message workflows. Fortinet's temporary workaround is to disable IBE; account for the effect on users who rely on it.[1], [5]
Known Exploited Vulnerability (KEV)
CISA added CVE-2026-104286 to its KEV catalog on October 1, 2026. This establishes known exploitation, not compromise of any particular appliance.[2], [5]
Version-scope discrepancy
Fortinet's advisory summary and government notices list branches 7.2, 7.4, 7.6, and 8.0; structured CNA data also lists 7.0. Verify 7.0 status directly with Fortinet.[6], [5], [4]

Framework mappings

Root Cause Analysis

Fortinet describes CVE-2026-104286 as an unauthenticated path-traversal flaw that can write arbitrary files through HTTP or HTTPS requests. The vendor's firmware is closed source, and the public advisory does not provide vulnerable source lines or a source patch diff; this article does not invent them. Public government advisories confirm the arbitrary-file-write impact, exploitation, and version guidance, but do not describe FortiMail's internal handler. Fortinet's advisory is the source for the IBE-disable or web-access-restriction workaround and the published IOCs. Contain and investigate the appliance, then apply the product-appropriate fixed release; a clean IOC check alone is not proof of safety. The CVE record's prose description lists 7.2.0–7.2.9, 7.4.0–7.4.8, 7.6.0–7.6.6, and 8.0.0–8.0.1. Its structured version table gives shorter upper bounds for 7.4 and 7.6 and additionally lists 7.0.0–7.0.9, unlike the public government summaries. The same record's solutions section lists upcoming 7.4.8, 7.6.6, 8.0.1, and 7.2.10, conflicting with both its affected-range data and the October 1 Canadian advisory. Use that dated government advisory as the published operational guidance, and confirm current release availability and the 7.0 scope with Fortinet; do not infer a fixed build from the conflicting CNA fields.[1], [3], [5], [4], [6], [7]

Operator matrix: branch scope and first response

AreaWhat authoritative sources sayDefender action
FortiMail 7.0NVD/CNA data lists 7.0.0–7.0.9; the Canadian and French government summaries do not list branch 7.0. The same record’s prose and structured table also disagree on the 7.4 and 7.6 upper bounds. The record’s solutions section also lists upcoming but lower builds (7.4.8, 7.6.6, 8.0.1, and 7.2.10), which conflict with its affected ranges and the Canadian advisory.Ask Fortinet to confirm the branch status; do not infer that an omitted branch is safe.
FortiMail 7.2The Canadian advisory says to upgrade to branch 7.4 or later.Plan migration to a fixed supported branch; do not assume a 7.2 patch exists.
FortiMail 7.4 / 7.6 / 8.0The Canadian advisory lists fixes at 7.4.9, 7.6.7, and 8.0.2, respectively.Use Canada advisory AV26-989 as the published build guidance; verify availability and support in Fortinet’s current bulletin before upgrading. Do not rely on the lower CNA solution cutoffs.
Containment and investigationFortinet reports exploitation and publishes IOCs; its workaround is to disable IBE or restrict web access.Preserve evidence, apply the workaround, review the vendor IOCs, then patch and assess compromise.

Step-by-Step Attack Flow

Step 1

An unauthenticated request reaches the web workflow

Fortinet says crafted HTTP or HTTPS requests can trigger the flaw without authentication. The public advisory does not disclose the internal handler or exact source implementation.[1], [5], [4]

Step 2

Path handling escapes the intended file boundary

The vendor classifies the issue as path traversal (CWE-22), allowing an arbitrary file write on the underlying FortiMail system. Do not infer a specific persistence mechanism from the CVE description alone.[1], [6], [5]

Step 3

Written files can create further system impact

Fortinet rates the issue CVSS 3.1 9.8 Critical and reports active exploitation. The vendor advisory contains the current compromise indicators and should guide investigation.[1], [5], [4]

Step 4

Mitigate, preserve evidence, and patch

Disable IBE or remove public reachability/restrict web access to trusted networks. Preserve logs and configuration, check Fortinet IOCs, then install the fixed release for the appliance's branch.[1], [5]

Source Code: Flaw vs. Secure Implementation

FortiMail firmware source and the vendor patch diff are not public, so this is a generic Python defense pattern, not Fortinet code or a reproduction. It opens a trusted directory once, uses a server-generated opaque filename, and creates a new regular file relative to that directory descriptor with exclusive creation and no-follow flags. It is POSIX-specific and fails closed when required flags are unavailable. For nested paths, walk one validated component at a time using directory descriptors; never check a string path and later reopen it by name. Apply Fortinet’s supported product update or workaround to remediate CVE-2026-104286. All components of the configured root path, including its parent directories, must remain administrator-controlled; O_NOFOLLOW protects only the final component when opening that root.

Source excerpt: Generic illustrative path-boundary example; not FortiMail source

UNPATCHED FLAW
from pathlib import Path

def destination(root: Path, request_path: str) -> Path:
    # Illustrates the unsafe design: caller input is joined
    # to a trusted directory without a containment check.
    return root / request_path
HARDENED SECURE PATCH
import os
import uuid

# Open the trusted, service-owned directory once; its path ancestors must stay administrator-controlled.

def open_upload_root(root):
    required = ("O_DIRECTORY", "O_NOFOLLOW")
    if not all(hasattr(os, flag) for flag in required) or os.open not in os.supports_dir_fd:
        raise RuntimeError("POSIX directory protections unavailable")
    flags = os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW
    return os.open(root, flags)

# Do not turn a request path into a filesystem path; generate an opaque name.
# O_EXCL fails if a name exists; O_NOFOLLOW rejects a final symlink.
ROOT_FD = open_upload_root("/srv/app-private/uploads")


def create_upload_file():
    name = uuid.uuid4().hex
    flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW
    fd = os.open(name, flags, 0o600, dir_fd=ROOT_FD)
    return name, fd

Engineering & System Hardening Checklist

Sources