Skip to content

keraattin/CVE-2026-35616

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 

Repository files navigation

CVE-2026-35616 - FortiClient EMS Pre-Authentication API Bypass to RCE

CVE-2026-35616 CVSS 9.1 CISA KEV CWE-284

TL;DR

A critical authentication bypass in Fortinet FortiClient EMS 7.4.5 and 7.4.6 allows a completely unauthenticated, remote attacker to bypass API authentication by spoofing a single HTTP header (X-SSL-CLIENT-VERIFY). The flaw exists because the Django middleware trusts client certificate metadata from user-controlled headers, not just from the trusted reverse proxy. This gives attackers full administrative API access - and from there, arbitrary code execution on managed endpoints across the enterprise.

Actively exploited since March 31, 2026. Added to CISA KEV on April 6, 2026.


Table of Contents


Quick Facts

Field Detail
CVE ID CVE-2026-35616
Vendor Fortinet
Product FortiClient Enterprise Management Server (EMS)
Affected Versions 7.4.5, 7.4.6
Not Affected 7.2.x branch, 7.4.4 and earlier
CVSS v3.1 9.1 (Critical)
CWE CWE-284 - Improper Access Control
Attack Vector Network
Authentication None required
User Interaction None
Exploit Maturity Exploited in the wild
CISA KEV Added April 6, 2026 (deadline: April 9, 2026)
Patch Hotfix available; full fix in 7.4.7
Credited To Simo Kohonen (Defused Cyber), Nguyen Duc Anh

What is FortiClient EMS?

FortiClient Enterprise Management Server (EMS) is Fortinet's centralized endpoint management platform. It serves as the command-and-control layer for deploying, configuring, and monitoring FortiClient agents across an organization. Think of it as the brain that governs every endpoint in a Fortinet-managed environment:

  • Pushes security policies and VPN profiles to endpoints
  • Manages endpoint compliance and posture checks
  • Distributes software updates and patches
  • Integrates with FortiGate firewalls for Zero Trust Network Access (ZTNA)
  • Stores and manages endpoint telemetry, certificates, and credentials

When an attacker gains administrative access to EMS, they essentially own the keys to every managed endpoint in the organization.


Vulnerability Deep Dive

The Architecture

FortiClient EMS uses a fairly standard web application stack behind the scenes:

+----------------+          +----------------+          +----------------+
|   Browser /    |  HTTPS   |    Apache      |   WSGI   |    Django      |
|   API Client   | -------> |   (mod_ssl)    | -------> |    Backend     |
+----------------+          +----------------+          +----------------+

When mutual TLS (mTLS) is configured, Apache's mod_ssl handles the client certificate verification. After validating the certificate, Apache passes the verification result downstream to Django through trusted WSGI environment variables:

  • SSL_CLIENT_VERIFY - The verification status (SUCCESS, NONE, FAILED)
  • SSL_CLIENT_S_DN - The Subject Distinguished Name from the certificate
  • SSL_CLIENT_SERIAL - The certificate serial number

This is the standard and secure pattern. The problem is in how the Django middleware reads this data.

Where It Breaks

In FortiClient EMS 7.4.5 and 7.4.6, the Django authentication middleware was modified to also accept this same information from HTTP request headers:

  • X-SSL-CLIENT-VERIFY
  • X-SSL-CLIENT-S-DN
  • X-SSL-CLIENT-SERIAL

This was likely added to support reverse proxy deployments where Apache isn't the TLS termination point. However, the middleware doesn't distinguish between these two sources. It checks the WSGI variables first, but if they're absent (no mTLS configured, or a direct connection), it falls back to the HTTP headers - which any client can set.

Here's the conceptual breakdown:

SECURE PATH (intended):
  Apache mod_ssl validates cert --> sets WSGI env vars --> Django reads env vars  [OK]

INSECURE PATH (the vulnerability):
  Attacker sets HTTP headers directly --> Django reads headers --> Trusts them  [FAIL]

The middleware effectively trusts the client to self-attest their own certificate verification status. That's like a bouncer asking someone "Hey, did the other bouncer already check your ID?" and letting them in when they say "yes."

The Attack Flow

Step 1: Attacker sends a POST request to an EMS API endpoint
        with these headers:
        
        X-SSL-CLIENT-VERIFY: SUCCESS
        X-SSL-CLIENT-S-DN: CN=admin
        X-SSL-CLIENT-SERIAL: 0000000000000001

Step 2: Django middleware checks for WSGI env vars → not present
        Falls back to HTTP headers → finds X-SSL-CLIENT-VERIFY: SUCCESS

Step 3: Middleware treats request as authenticated with admin identity

Step 4: Attacker has full administrative API access

Step 5: From the admin API, attacker can:
        - Push malicious policies to all managed endpoints
        - Extract stored credentials and certificates
        - Deploy payloads via software distribution
        - Modify ZTNA configurations
        - Pivot into the broader network

The entire attack requires a single HTTP request. No brute-forcing, no credential stuffing, no social engineering. Just one forged header.


Impact Analysis

The severity here goes beyond the server itself. FortiClient EMS is a force multiplier - compromising it gives an attacker leverage over every managed endpoint:

Immediate Impact:

  • Full administrative control over the EMS console
  • Access to all stored endpoint configurations, credentials, and certificates
  • Ability to read/modify/delete endpoint policies
  • Access to VPN configurations and ZTNA settings

Downstream Impact (via managed endpoints):

  • Malware deployment to all managed devices via software distribution
  • Credential harvesting from endpoint telemetry
  • Disable or weaken security controls on all managed endpoints
  • Lateral movement via VPN/ZTNA configuration manipulation
  • Persistent backdoor access through policy-based payload delivery

Enterprise Risk:

  • In a typical enterprise deployment, EMS manages hundreds to thousands of endpoints
  • A single exploited EMS instance can lead to organization-wide compromise
  • FortiClient EMS is often positioned in a trusted network zone with broad access

Affected Versions

Version Status
FortiClient EMS 7.4.6 Vulnerable
FortiClient EMS 7.4.5 Vulnerable
FortiClient EMS 7.4.4 and earlier Not affected
FortiClient EMS 7.2.x Not affected

Exploitation Timeline

Date Event
~Late March 2026 Vulnerability discovered and reported by Simo Kohonen and Nguyen Duc Anh
March 31, 2026 First exploitation attempts recorded against honeypots (Defused Cyber)
April 4, 2026 Fortinet releases emergency hotfixes for 7.4.5 and 7.4.6
April 6, 2026 CISA adds CVE-2026-35616 to KEV catalog (deadline: April 9, 2026)
April 13, 2026 This detection toolkit published

Detection

Python Scanner

The Python script tests multiple API endpoints using a differential-response technique.

How it works:

  1. Fingerprinting - Identifies FortiClient EMS via HTTP response body and headers
  2. Baseline request - Sends a POST to each API endpoint without spoof headers (expects HTTP 401 Unauthorized)
  3. Spoofed request - Sends the same request with X-SSL-CLIENT-VERIFY: SUCCESS injected
  4. Comparison - If the status code changes from 401 to anything else (typically 500 or 200), the authentication bypass is confirmed

No exploitation payload is ever sent. The test is safe for production.

Usage:

# Install dependencies (only stdlib needed for this script)
pip install -r requirements.txt

# Single target
python CVE-2026-35616_FortiClientEMS_detector.py -t 192.168.1.100

# Custom port
python CVE-2026-35616_FortiClientEMS_detector.py -t ems.corp.local -p 8443

# Bulk scan from file
python CVE-2026-35616_FortiClientEMS_detector.py -f targets.txt

# JSON output saved to file
python CVE-2026-35616_FortiClientEMS_detector.py -t 192.168.1.100 --json -o results.json

# With SSL certificate verification enabled
python CVE-2026-35616_FortiClientEMS_detector.py -t 192.168.1.100 --verify-ssl

# Increased timeout for slow networks
python CVE-2026-35616_FortiClientEMS_detector.py -t 192.168.1.100 --timeout 20

Options:

Flag Description Default
-t, --target Target IP or hostname -
-f, --file File with targets, one per line (lines starting with # are skipped) -
-p, --port Target port 443
--timeout Connection timeout in seconds 10
--verify-ssl Enable SSL certificate verification Disabled
--json Output results in JSON format Off
-o, --output Save results to a file -

Example output:

╔══════════════════════════════════════════════════════════════╗
║  CVE-2026-35616 - FortiClient EMS Auth Bypass Detector     ║
║  Pre-Authentication API Access Bypass → Privilege Escalation║
║  CVSS: 9.1 (Critical) | CISA KEV: Active Exploitation      ║
╚══════════════════════════════════════════════════════════════╝

[*] Scanning 192.168.1.100:443...

Target: 192.168.1.100:443
============================================================
  [*] FortiClient EMS detected (Version: Unknown)

  Vulnerability Test Results:
    [VULNERABLE] /api/v1/auth/signin  Baseline: 401 → Spoofed: 500
    [VULNERABLE] /api/v1/system/status  Baseline: 401 → Spoofed: 500
    [NOT VULN] /api/v1/endpoints  Baseline: 401 → Spoofed: 401

  [!] TARGET IS LIKELY VULNERABLE TO CVE-2026-35616
      Pre-authentication API bypass confirmed. Apply hotfix immediately!
      Remediation: Upgrade to FortiClient EMS 7.4.7 or apply the hotfix

Nmap NSE Script

# Install the NSE script
sudo cp CVE-2026-35616_FortiClientEMS.nse /usr/share/nmap/scripts/
sudo nmap --script-updatedb

# Basic scan
nmap -p 443 --script CVE-2026-35616_FortiClientEMS <target>

# Scan a subnet
nmap -p 443 --script CVE-2026-35616_FortiClientEMS 10.0.0.0/24

# Scan multiple targets from a file
nmap -p 443 --script CVE-2026-35616_FortiClientEMS -iL targets.txt

# With service version detection
nmap -sV -p 443 --script CVE-2026-35616_FortiClientEMS <target>

Example Nmap output:

PORT    STATE SERVICE
443/tcp open  https
| CVE-2026-35616_FortiClientEMS:
|   VULNERABLE:
|   FortiClient EMS Pre-Authentication API Bypass
|     State: VULNERABLE
|     IDs:  CVE:CVE-2026-35616
|     Risk factor: Critical (CVSS: 9.1)
|     Disclosure date: 2026-04-04
|     Extra information:
|       Affected endpoints: 2
|       Remediation: Apply hotfix for FortiClient EMS 7.4.5/7.4.6 or upgrade to 7.4.7
|       CISA KEV deadline: April 9, 2026
|     References:
|       https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2026-35616
|_      https://www.cisa.gov/known-exploited-vulnerabilities-catalog

Manual Verification

If you want to confirm manually with curl:

# Step 1: Baseline - should return 401
curl -sk -X POST https://<TARGET>:443/api/v1/auth/signin \
  -H "Content-Type: application/json" \
  -d '{}' \
  -o /dev/null -w "%{http_code}\n"

# Step 2: Spoofed - if returns anything other than 401, likely vulnerable
curl -sk -X POST https://<TARGET>:443/api/v1/auth/signin \
  -H "Content-Type: application/json" \
  -H "X-SSL-CLIENT-VERIFY: SUCCESS" \
  -H "X-SSL-CLIENT-S-DN: CN=admin" \
  -H "X-SSL-CLIENT-SERIAL: 0000000000000001" \
  -d '{}' \
  -o /dev/null -w "%{http_code}\n"

If the first returns 401 and the second returns 500 or 200, the instance is vulnerable.


Indicators of Compromise

Watch for these signs in your environment:

  • Anomalous API requests containing X-SSL-CLIENT-VERIFY headers from non-proxy sources
  • Unexpected policy changes pushed to endpoints without admin session activity
  • New admin accounts or modified credentials in EMS without corresponding activity logs
  • Unusual FortiClient agent behavior on managed endpoints (new software installations, policy changes)
  • Apache access logs showing API calls without corresponding mTLS handshakes
  • Honeypot/IDS alerts for requests with certificate-related header injection

Log sources to review:

  • FortiClient EMS application logs
  • Apache access and error logs
  • FortiClient agent logs on managed endpoints
  • Network flow data showing connections to EMS API ports

Remediation

Immediate actions (do these now):

  1. Apply the hotfix - Fortinet released emergency hotfixes for FortiClient EMS 7.4.5 and 7.4.6 on April 4, 2026
  2. Restrict network access - Limit access to the EMS management interface to trusted admin networks only (firewall rules, ACLs)
  3. Monitor API activity - Enable detailed logging and watch for anomalous API access patterns

Short-term (this week):

  1. Upgrade to FortiClient EMS 7.4.7 when available for the complete fix
  2. Audit endpoint configurations - Check all managed endpoints for unauthorized policy changes
  3. Rotate credentials - Change all admin passwords and regenerate any certificates managed by EMS
  4. Review managed endpoints - Scan for signs of malware deployment or unauthorized configuration changes

Long-term:

  1. Network segmentation - Ensure EMS is in an isolated management VLAN with strict access controls
  2. WAF/reverse proxy rules - Deploy rules to strip X-SSL-CLIENT-VERIFY, X-SSL-CLIENT-S-DN, and X-SSL-CLIENT-SERIAL headers from incoming requests at the network edge
  3. Monitoring - Implement alerting on any API access without valid mTLS sessions

References


Author

Kerem Oruç - Cybersecurity Engineer

About

CVE-2026-35616 - FortiClient EMS Pre-Authentication API Bypass (CVSS 9.1, CISA KEV). Python & Nmap NSE detection scripts with full technical breakdown. One forged HTTP header bypasses authentication on FortiClient EMS 7.4.5–7.4.6, granting full admin API access to all managed endpoints.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors