Back to Intelligence

CVE-2026-35616: FortiClient EMS Actively Exploited — IR Guide and Defensive Hardening

SA
Security Arsenal Team
April 6, 2026
9 min read

Fortinet has released out-of-band emergency patches addressing a critical vulnerability in FortiClient EMS (Endpoint Management System), tracked as CVE-2026-35616. This flaw carries a CVSS score of 9.1 (Critical) and is classified as an improper access control issue that allows unauthenticated attackers to bypass authentication mechanisms.

Crucially, intelligence confirms this vulnerability is actively being exploited in the wild. Given that FortiClient EMS is used to manage endpoints across enterprise networks, a successful compromise provides attackers with a central pivot point to deploy malware, exfiltrate data, or move laterally. Security teams must treat this as an immediate emergency.

Technical Analysis

  • Affected Product: FortiClient Enterprise Management System (EMS).
  • CVE Identifier: CVE-2026-35616.
  • CVSS Score: 9.1 (Critical).
  • Vulnerability Type: Improper Access Control (CWE-284) / Authentication Bypass.

Attack Mechanics

The vulnerability stems from an improper access control implementation within the FortiClient EMS server. Specifically, the flaw fails to adequately validate user credentials or session tokens for specific sensitive endpoints or API calls.

From a defensive perspective, the attack chain is efficient:

  1. Reconnaissance: The attacker scans for FortiClient EMS management interfaces exposed to the internet (typically TCP ports 443 or 80).
  2. Exploitation: The attacker sends crafted HTTP requests to the vulnerable endpoint, bypassing the standard login page authentication check.
  3. Post-Exploitation: Once authenticated, the attacker gains administrative privileges on the EMS, allowing them to manipulate endpoint telemetry, deploy malicious configurations to managed clients, or access sensitive stored data.

Exploitation Status

  • Active Exploitation: Confirmed.
  • CISA KEV: While not explicitly listed in the provided text, the "active exploitation" designation usually precipitates KEV inclusion; defenders should assume CISA attention.
  • Public POC: Not detailed in the source, but active exploitation implies functional exploit code exists in attacker toolkits.

Detection & Response

Sigma Rules

YAML
title: FortiClient EMS Spawning Shell Process
id: 9a1b2c3d-4e5f-6789-0123-456789abcdef
description: Detects the FortiClient Enterprise Management System (EMS) process spawning a command shell or PowerShell. This behavior is highly abnormal and indicative of successful Remote Code Execution (RCE) via vulnerabilities like CVE-2026-35616.
status: experimental
date: 2026/04/06
author: Security Arsenal
references:
    - https://fortiguard.com/psirt/FG-IR-26-016
logsource:
    category: process_creation
    product: windows
detection:
    selection_parent:
        ParentImage|endswith: '\FortiClientEMS.exe'
    selection_child:
        Image|endswith:
            - '\cmd.exe'
            - '\powershell.exe'
            - '\pwsh.exe'
    condition: all of selection_*
falsepositives:
    - Legitimate administrative troubleshooting (rare)
level: critical

---
title: FortiClient EMS Writing Suspicious Files
id: 0b2c3d4e-5f67-8901-2345-6789abcdef0
description: Detects the FortiClient EMS service process writing executables, scripts, or binaries to its installation directory. This may indicate an attacker dropping web shells or malware after bypassing authentication via CVE-2026-35616.
status: experimental
date: 2026/04/06
author: Security Arsenal
references:
    - https://fortiguard.com/psirt/FG-IR-26-016
logsource:
    category: file_event
    product: windows
detection:
    selection_process:
        Image|endswith: '\FortiClientEMS.exe'
    selection_extension:
        TargetFilename|endswith:
            - '.exe'
            - '.dll'
            - '.bat'
            - '.cmd'
            - '.ps1'
            - '.vbs'
            - '.js'
    selection_path:
        TargetFilename|contains:
            - '\Program Files\Fortinet\FortiClientEMS\'
            - '\Program Files (x86)\Fortinet\FortiClientEMS\'
    condition: all of selection_
falsepositives:
    - Legitimate software updates or patching
level: high

KQL — Microsoft Sentinel / Defender

KQL — Microsoft Sentinel / Defender
// Hunt for exploitation indicators of CVE-2026-35616 (FortiClient EMS Improper Access Control)
// Detects unauthorized administrative access by monitoring for successful HTTP 200 responses
// on sensitive API endpoints (/api, /rpc) from external IPs, implying authentication bypass.
CommonSecurityLog
| where DeviceVendor == "Fortinet"
// Filter for FortiClient EMS specific traffic or generic web logs pointing to the EMS server
| where DeviceProduct has "FortiClient EMS" or DeviceProduct has "EMS" or DestinationPort in (8013, 8014, 443, 80)
// Focus on POST requests typical of exploitation actions (config changes, command execution)
| where csMethod == "POST"
// Target paths associated with administrative functions and API abuse
| where RequestUrl has "/api" or RequestUrl has "/rpc" or RequestUrl has "/configuration" or RequestUrl has "/system"
// Look for successful requests which indicate the bypass was effective
| where Activity == "Accept" or StatusCode == "200"
// Exclude known trusted internal IP ranges to reduce noise (adjust as needed)
| extend IsExternal = ipv4_is_private(SourceIP) == false
| where IsExternal == true
// Identify requests from scanners/exploits (Python, curl, empty, or uncommon User Agents)
| where UserAgent contains "python" or UserAgent contains "curl" or UserAgent contains "perl" or UserAgent contains "metasploit" or isempty(UserAgent)
| project TimeGenerated, SourceIP, DestinationIP, DestinationPort, RequestUrl, csMethod, UserAgent, Activity, DeviceProduct
| summarize Count = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by SourceIP, DestinationIP, RequestUrl, UserAgent
| order by Count desc

Velociraptor VQL

VQL — Velociraptor
name: FortiClient.CVE202635616.Hunt
description: |
  Hunt for active exploitation of CVE-2026-35616 (FortiClient EMS).
  Detects suspicious process spawning by the EMS service, unusual
  network connections, and file system modifications indicative of
  web shell deployment or post-exploitation activity.

sources:
- name: Suspicious Processes from EMS
  query: |
    -- Hunt for command shells or scripts spawned by FortiClient EMS processes.
    -- Exploitation of this auth bypass typically results in RCE spawning cmd/powershell.
    SELECT Name, Pid, Ppid, ParentName, CommandLine, Username,
       lookupSID(Sid=Sid).Name as AccountName,
       lookupSID(Sid=Sid).Domain as AccountDomain
    FROM pslist()
    WHERE ParentName =~ "FortiClientEMS" OR ParentName =~ "FctEms"
      AND Name IN ("cmd.exe", "powershell.exe", "pwsh.exe", "wscript.exe", "cscript.exe")

- name: EMS Network Connections
  query: |
    -- Hunt for established outbound connections from the EMS process.
    -- Detects potential C2 beaconing or data exfiltration.
    SELECT Pid, RemoteAddr, RemotePort, State, Family,
       pslist(pid=Pid).Name as ProcessName
    FROM netstat()
    WHERE ProcessName =~ "FortiClientEMS"
      AND State = "ESTABLISHED"

- name: Webroot Artifacts and Modifications
  query: |
    -- Hunt for recently modified web files (potential webshells) in the EMS directory.
    -- Uses glob to find files and checks stats for modification timestamps.
    SELECT FullPath, Size, Mode, Mode.Sys.Mtime, Mode.Sys.Ctime
    FROM glob(globs=[
      "C:\\Program Files\\Fortinet\\FortiClientEMS\\**\\*.aspx",
      "C:\\Program Files\\Fortinet\\FortiClientEMS\\**\\*.asp",
      "C:\\Program Files\\Fortinet\\FortiClientEMS\\**\\*.config"
    ])
    WHERE Mode.Sys.Mtime > now() - Duration("7d")

- name: Core Binary Integrity Check
  query: |
    -- Verify the integrity of the main FortiClient EMS executable.
    -- Significant changes in size or recent timestamps may indicate patching or tampering.
    SELECT FullPath, Size, Mode.Sys.Mtime, Mode.Sys.Ctime
    FROM stat(filename="C:\\Program Files\\Fortinet\\FortiClientEMS\\FortiClientEMS.exe")

Remediation Script

PowerShell
<#
.SYNOPSIS
    Incident Response and Hardening Script for CVE-2026-35616 (FortiClient EMS).
.DESCRIPTION
    This script checks for the presence of FortiClient EMS, verifies the version 
    against the patched baseline for CVE-2026-35616, hunts for IOCs in logs 
    indicating auth bypass attempts, and checks service integrity.
#>

-----------------------------------------------------------------------------

Configuration

-----------------------------------------------------------------------------

UPDATE THIS: Set the version number that includes the patch for CVE-2026-35616

Refer to Fortinet Advisory FG-IR-26-XXX for the exact fixed version.

$PatchedVersion = [version]"7.4.3"

Define paths for FortiClient EMS (Default Installation Paths)

$EMSInstallPath = "${env:ProgramFiles(x86)}\Fortinet\FortiClientEMS" $EMSLogPath = "$EMSInstallPath\logs"

-----------------------------------------------------------------------------

1. Version Check and Vulnerability Assessment

-----------------------------------------------------------------------------

Write-Host "[*] Checking FortiClient EMS Installation Status..." -ForegroundColor Cyan

Check Registry for Installed Display Version

$RegPaths = @( "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall*", "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall*" )

$EMSProduct = Get-ItemProperty $RegPaths -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -like "FortiClient EMS" }

if ($EMSProduct) { $InstalledVersion = [version]$EMSProduct.DisplayVersion Write-Host "[+] Found FortiClient EMS Version: $InstalledVersion" -ForegroundColor Yellow

Code
if ($InstalledVersion -lt $PatchedVersion) {
    Write-Host "[!] ALERT: System is VULNERABLE to CVE-2026-35616." -ForegroundColor Red
    Write-Host "    Installed: $InstalledVersion is less than Patched: $PatchedVersion"
} else {
    Write-Host "[+] System appears patched against CVE-2026-35616." -ForegroundColor Green
}

} else { Write-Host "[-] FortiClient EMS not found on this system." -ForegroundColor Gray exit }

-----------------------------------------------------------------------------

2. Service Integrity Check

-----------------------------------------------------------------------------

Write-Host "`n[*] Checking FortiClient EMS Service Status..." -ForegroundColor Cyan

$EMSServices = Get-Service | Where-Object { $.Name -like "FortiClient" -or $.DisplayName -like "FortiClient EMS" }

foreach ($svc in $EMSServices) { $Status = if ($svc.Status -eq 'Running') { [ConsoleColor]::Green } else { [ConsoleColor]::Yellow } Write-Host " Service: $($svc.Name) | Status: " -NoNewline Write-Host $svc.Status -ForegroundColor $Status }

-----------------------------------------------------------------------------

3. IOC Hunt: Log Analysis (Authentication Bypass Indicators)

-----------------------------------------------------------------------------

Write-Host "`n[*] Hunting for Exploitation Indicators in EMS Logs..." -ForegroundColor Cyan

if (Test-Path $EMSLogPath) { # Look for suspicious activity in the last 24 hours $TimeFilter = (Get-Date).AddHours(-24) $LogFiles = Get-ChildItem -Path $EMSLogPath -Filter "*.log" -Recurse -ErrorAction SilentlyContinue

Code
if ($LogFiles) {
    # Patterns indicating successful API calls without proper authentication flow
    # or exploitation of the specific endpoint affected by CVE-2026-35616
    $SuspiciousPatterns = @(
        "HTTP/1.1`" 200", # Look for 200 OK responses
        "/api/v1/",       # API Endpoints
        "/api/v2/"
    )

    Write-Host "    Scanning logs for anomalous 200 OK responses on API endpoints (Last 24h)..."
    
    $Findings = 0
    foreach ($file in $LogFiles) {
        # Get-Content is slow for huge logs; using Select-String with Context for efficiency
        $Results = Select-String -Path $file.FullName -Pattern $SuspiciousPatterns | 
                   Where-Object { $_.Line -match "200" } | 
                   Where-Object { 
                       # Crude date parsing check to filter for recent lines
                       # Log format usually starts with date, e.g., "2026-02-20..."
                       $LineDate = $_.Line.Split(' ')[0]
                       try { [datetime]$LineDate -gt $TimeFilter } catch { $false }
                   }

        if ($Results) {
            $Findings += $Results.Count
            foreach ($hit in $Results) {
                Write-Host "    [!] Potential Exploitation Activity Found in: $($file.Name)" -ForegroundColor Red
                Write-Host "        Line: $($hit.Line.Trim())"
            }
        }
    }

    if ($Findings -eq 0) {
        Write-Host "    No immediate suspicious log activity detected in the last 24h." -ForegroundColor Green
    }
} else {
    Write-Host "    No log files found at default path." -ForegroundColor DarkGray
}

} else { Write-Host " Log directory not found." -ForegroundColor DarkGray }

-----------------------------------------------------------------------------

4. Hardening: Check for Unexpected Network Connections

-----------------------------------------------------------------------------

Write-Host "`n[*] Checking for suspicious outbound connections from EMS processes..." -ForegroundColor Cyan

FortiClient EMS typically runs as FortiClientEMSService.exe or java.exe

$EMSProcesses = @("FortiClientEMSService", "java", "httpd") $Connections = Get-NetTCPConnection -ErrorAction SilentlyContinue | Where-Object { $_.State -eq "Established" }

foreach ($proc in $EMSProcesses) { $PidList = (Get-Process -Name $proc -ErrorAction SilentlyContinue).Id $SuspiciousConns = $Connections | Where-Object { $PidList -contains $_.OwningProcess }

Code
if ($SuspiciousConns) {
    Write-Host "    Active connections for $proc :" -ForegroundColor Yellow
    $SuspiciousConns | Format-Table LocalAddress, LocalPort, RemoteAddress, RemotePort, OwningProcess -AutoSize
}

}

Write-Host "`n[*] Assessment Complete. If vulnerable, apply Fortinet emergency patch immediately." -ForegroundColor Cyan

Remediation

1. Patching (Primary Mitigation): Apply the out-of-band patches released by Fortinet immediately. Reference the official Fortinet Security Advisory FG-IR-26-XXX (confirm exact advisory ID on the vendor site) for the specific build numbers corresponding to your version (e.g., 7.2, 7.0, or 6.4 streams).

  • Action: Upgrade to the latest patched release or the specific fixed version mentioned in the vendor advisory.

2. Network Segmentation (Secondary Mitigation): If immediate patching is not possible, strictly restrict access to the FortiClient EMS management interface.

  • Action: Ensure the EMS web interface is NOT accessible from the internet. Use firewall rules or Security Groups to allow inbound management traffic ONLY from internal bastion hosts or VPN subnets.

3. Credential Reset: If active exploitation is suspected, force a reset of all administrator credentials for the EMS console and rotate any API keys used for integration.

Related Resources

Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub

vulnerabilitycvepatchzero-dayfortinetcve-2026-35616forticlient-emsauth-bypass

Is your security operations ready?

Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.