← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
CVE-2024-55591 · CWE-288 · Disclosed 2025-01-14

An Authentication Bypass Using an Alternate Path or Channel vulnerability [CWE-288] affecting FortiOS…

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is a side door straight into the guard booth, not a harder way through the front gate

CVE-2024-55591 is an unauthenticated auth bypass in the FortiOS/FortiProxy management plane. Fortinet says crafted requests to the Node.js websocket module can yield super_admin privileges; affected versions are FortiOS 7.0.0–7.0.16, FortiProxy 7.0.0–7.0.19, and FortiProxy 7.2.0–7.2.12, with fixes in FortiOS 7.0.17, FortiProxy 7.0.20, and FortiProxy 7.2.13.

The vendor's CRITICAL label matches reality once you focus on how these boxes are used: they sit on the perimeter, hold policy control, VPN access, and routing trust, and this bug has confirmed in-the-wild exploitation and KEV status. The only real downward pressure is that the management interface must be reachable, but that friction is not enough to move this out of CRITICAL because exposed admin planes were exactly what attackers targeted in observed campaigns.

"If the FortiGate admin plane is internet-reachable, this is initial access with firewall-level blast radius."
02 · The Attack Path

5 steps from start to impact.

STEP 01

Find exposed admin planes

Attackers use internet-wide search tooling such as Censys and commodity scanning to identify Fortinet management interfaces exposed over HTTPS. This is a classic perimeter-device hunting problem, not a deep-internal niche exploit.
Conditions required:
  • FortiGate/FortiProxy HTTP or HTTPS administrative interface is reachable from the internet
  • Target is running an affected version
Where this breaks in practice:
  • Many mature enterprises keep management off the public internet or pin it to jump-host IPs
  • Version fingerprinting is imperfect from the outside, so some scans produce false targets
Detection/coverage: External attack-surface tools and internet exposure monitoring catch this well; internal vuln scanners often miss it if they cannot reach the management plane.
STEP 02

Open a pre-auth WebSocket

Using a custom Python client or the watchTowr research tooling, the attacker sends crafted websocket upgrade traffic to the Fortinet Node.js-backed management component. The exploit path abuses pre-auth handling in the websocket flow rather than stealing valid credentials.
Conditions required:
  • HTTPS management service responds
  • Node.js websocket path is exposed on the target build
Where this breaks in practice:
  • WAFs rarely sit in front of firewall admin planes
  • TLS inspection usually does not apply to inbound management sessions
Detection/coverage: Network IDS may see odd websocket upgrade patterns, but generic scanners will not reliably prove exploitability without active checks.
STEP 03

Race or abuse the auth context to become super_admin

Per watchTowr's reverse engineering, the chain involves pre-auth websocket creation, a local_access_token shortcut, and a race into the CLI/Telnet auth path where no unique secret is needed to assert a privileged context. The attacker can effectively choose an access profile and land in the appliance CLI as an administrator.
Conditions required:
  • Target is vulnerable and unpatched
  • Exploit timing lands correctly or the crafted request path succeeds
Where this breaks in practice:
  • This is not a one-packet memory corruption bug; the attacker needs the right protocol behavior
  • Fortinet notes that knowing an admin username helps CLI login, though brute forcing usernames remains feasible
Detection/coverage: Best telemetry is on-box logging: successful admin login via jsconsole, Local_Process_Access, and suspicious admin object creation. Signature-only detection is incomplete.
STEP 04

Establish durable control on the appliance

Observed operators did not stop at ephemeral shell access. Fortinet and Arctic Wolf both describe attackers creating new admin accounts, creating local users, modifying groups and policies, and in some cases enabling SSL VPN access for persistence and pivoting.
Conditions required:
  • Attacker has gained super_admin privileges
  • Configuration changes are permitted and saved
Where this breaks in practice:
  • Change monitoring or config drift alerting can surface this quickly
  • Organizations with out-of-band config backups may detect unexpected deltas
Detection/coverage: Fortinet IoCs include ui="jsconsole", random admin usernames, and config changes under system.admin or SSL VPN groups.
STEP 05

Pivot through the firewall into the enterprise

Once the perimeter device is owned, the attacker can turn the firewall into an access broker: create VPN users, alter policy, proxy traffic, harvest config, and stage lateral movement into internal networks. This is why the blast radius is larger than 'one appliance compromised.'
Conditions required:
  • Internal networks, VPN settings, or trust relationships are present behind the device
  • The compromised box is a meaningful choke point in the environment
Where this breaks in practice:
  • Segmentation and identity controls still matter after initial access
  • EDR on downstream hosts can still stop follow-on intrusion activity
Detection/coverage: You need firewall config auditing, VPN account creation alerts, and downstream lateral-movement detections; endpoint tools do nothing until the attacker pivots past the appliance.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusConfirmed exploited. Fortinet says it is exploited in the wild, and Arctic Wolf tied pre-disclosure activity from mid-November 2024 to this vulnerability.
KEV statusYes. Added to CISA KEV on 2025-01-14 with a federal due date of 2025-01-21.
Proof-of-concept availabilityPublic research and tooling exist. watchTowr Labs published deep technical analysis plus a GitHub detection script and a PoC repo.
EPSS0.94124 from the user-supplied intel block — extremely high exploit probability and directionally consistent with real exploitation.
CVSS and interpretationCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H means unauthenticated remote takeover of the management plane with full confidentiality, integrity, and availability impact.
Affected versionsFortiOS 7.0.0–7.0.16; FortiProxy 7.0.0–7.0.19; FortiProxy 7.2.0–7.2.12. FortiOS 7.2, 7.4, and 7.6 are listed as not affected in Fortinet's advisory.
Fixed versionsUpgrade to FortiOS 7.0.17+, FortiProxy 7.0.20+, or FortiProxy 7.2.13+ per Fortinet PSIRT.
Observed operator behaviorFortinet observed random admin creation, local user creation, group/policy changes, and SSL VPN login using attacker-added users. Arctic Wolf observed public-exposure cases with jsconsole logins and follow-on configuration changes.
Exposure dataCensys reported 3,445,797 exposed FortiOS/FortiProxy devices total at the time of its advisory, including 51 exposed FortiProxy instances; 16% were geolocated in the United States. Censys notes not all exposed instances could be version-confirmed as vulnerable.
Disclosure and reportingFortinet published the advisory on 2025-01-14. Fortinet credits Sonny of watchTowr for the CSF-related vulnerability work later added to the same advisory stream.
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to CRITICAL (9.8/10)

The decisive factor is simple: this is unauthenticated remote compromise of a perimeter security appliance that is already confirmed under active exploitation. The only meaningful friction is management-plane exposure, but when that condition is met the attacker lands on one of the highest-blast-radius boxes in the enterprise.

HIGH Severity if administrative interface is internet-reachable
HIGH Assessment of active exploitation and KEV-driven urgency
MEDIUM Population-wide prevalence inside enterprises, because many shops do restrict management access

Why this verdict

  • Baseline stays near max: start from vendor/NVD criticality because the bug is AV:N/PR:N/UI:N on a perimeter device, not a niche internal service.
  • One real friction lowers it slightly: exploitation generally requires the HTTP/HTTPS administrative interface to be reachable, which narrows the exposed population versus 'every FortiGate on the internet.'
  • That discount gets erased by field evidence: CISA KEV on 2025-01-14, Fortinet-confirmed exploitation, and Arctic Wolf's pre-disclosure campaign reporting show attackers were already doing exactly this against exposed admin planes.
  • Blast radius is exceptional: super_admin on a firewall/VPN appliance means policy tampering, credential or config theft, rogue VPN access, and a clean path to internal-network pivoting.

Why not higher?

There is no higher bucket than CRITICAL, and this is close to the top of that range already. The one thing keeping it from a perfect 10 is that the attack path is not universal across all deployments; organizations that never expose the admin interface have materially less reachability.

Why not lower?

Downgrading this would ignore the two facts that matter most: active exploitation and initial-access utility on a perimeter choke point. This is not a post-compromise local bug, not an authenticated admin edge case, and not a narrow feature toggle affecting an obscure subset.

05 · Compensating Control

What to do — in priority order.

  1. Remove public admin exposure — Take the HTTP/HTTPS administrative interface off the public internet or pin it to explicit management-source IPs immediately, within hours because KEV/active exploitation overrides the normal timeline. This directly breaks step 1 of the attack chain and is Fortinet's preferred workaround.
  2. Apply restrictive local-in policy — If public removal is not immediately possible, restrict GUI access with Fortinet local-in-policy controls immediately, within hours so only jump hosts or admin networks can reach it. Fortinet explicitly prefers local-in policies over relying on trusthost alone.
  3. Disable Security Fabric if exposed and unpatched — For the CSF request variant described in Fortinet's advisory, disable Security Fabric from the CLI immediately, within hours if you cannot patch at once. This is a temporary blast-radius reduction, not a substitute for upgrading.
  4. Hunt for appliance persistence — Review Fortinet logs and configs for ui="jsconsole", Local_Process_Access, random admin creation, local user creation, SSL VPN group changes, and unexpected firewall policy edits immediately, within hours. Active exploitation means exposure may already equal compromise.
  5. Freeze new VPN/admin objects — Alert on or require review for any new local users, admin accounts, and SSL VPN group membership changes immediately, within hours. Fortinet and Arctic Wolf both observed attackers using those exact persistence patterns.
What doesn't work
  • MFA on admin accounts does not fix a pre-auth management-plane bypass; the attacker is not following the normal login flow.
  • Blocking the IoC srcip/dstip values from Fortinet logs does not help; Fortinet says those fields were attacker-generated parameters, not reliable source addresses.
  • trusthost by itself is not enough unless every GUI user is configured with it; Fortinet explicitly says local-in-policy is the preferred workaround.
  • Endpoint controls alone do nothing on the firewall itself; EDR only becomes useful after the attacker pivots beyond the appliance.
06 · Verification

Crowdsourced verification payload.

Run this from an auditor workstation that can reach the target's HTTPS management interface; invoke it exactly as python3 fortios_cve_2024_55591_check.py 10.0.0.1 443. It needs only network access to the admin port and does not require credentials or privileged local access; it performs a lightweight pre-auth websocket behavior check and prints VULNERABLE, PATCHED, or UNKNOWN.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
# CVE-2024-55591 pre-auth websocket behavior check
# Usage: python3 fortios_cve_2024_55591_check.py <host> [port]
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN, 3=USAGE

import base64
import os
import random
import socket
import ssl
import sys

TIMEOUT = 7


def build_request(host, path):
    key = base64.b64encode(os.urandom(16)).decode()
    headers = [
        f"GET {path} HTTP/1.1",
        f"Host: {host}",
        "User-Agent: noisgate-cve-2024-55591-check/1.0",
        "Upgrade: websocket",
        "Connection: Upgrade",
        f"Sec-WebSocket-Key: {key}",
        "Sec-WebSocket-Version: 13",
        "Origin: https://%s" % host,
        "\r\n",
    ]
    return "\r\n".join(headers).encode()


def recv_some(sock):
    data = b""
    try:
        while True:
            chunk = sock.recv(4096)
            if not chunk:
                break
            data += chunk
            if b"\r\n\r\n" in data:
                break
    except socket.timeout:
        pass
    return data


def main():
    if len(sys.argv) not in (2, 3):
        print("UNKNOWN")
        print("Usage: python3 fortios_cve_2024_55591_check.py <host> [port]", file=sys.stderr)
        sys.exit(3)

    host = sys.argv[1]
    port = int(sys.argv[2]) if len(sys.argv) == 3 else 443

    # Use a few candidate paths because deployed behavior can vary by build.
    candidates = [
        "/ws/events",
        "/ws/cli/open",
        "/ws/%d" % random.randint(10000, 99999),
    ]

    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE

    saw_rejection = False
    errors = []

    for path in candidates:
        try:
            raw = socket.create_connection((host, port), timeout=TIMEOUT)
            raw.settimeout(TIMEOUT)
            tls = ctx.wrap_socket(raw, server_hostname=host)
            req = build_request(host, path)
            tls.sendall(req)
            resp = recv_some(tls)
            tls.close()

            head = resp.decode(errors="ignore")
            if "101 Switching Protocols" in head:
                print("VULNERABLE")
                sys.exit(1)
            if any(code in head for code in ["401 Unauthorized", "403 Forbidden", "404 Not Found", "400 Bad Request"]):
                saw_rejection = True
                continue
            errors.append(f"{path}: unexpected response: {head[:120]!r}")
        except Exception as e:
            errors.append(f"{path}: {e}")

    if saw_rejection:
        print("PATCHED")
        sys.exit(0)

    print("UNKNOWN")
    if errors:
        print("; ".join(errors[:3]), file=sys.stderr)
    sys.exit(2)


if __name__ == "__main__":
    main()
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning: treat every internet-reachable FortiGate/FortiProxy management interface as potentially compromised until proven otherwise. Because this is KEV-listed and actively exploited, patch / mitigate immediately, within hours by removing public admin exposure or enforcing Fortinet's local-in restrictions, then hunt for jsconsole, Local_Process_Access, rogue admin/local users, and VPN/group changes before restoring trust; that is your noisgate mitigation SLA override. Complete firmware remediation to fixed builds within the noisgate remediation SLA of ≤90 days, but in any environment with exposed admin planes you should operationally handle the upgrade as an emergency change, not backlog work.

Sources

  1. Fortinet PSIRT FG-IR-24-535
  2. NVD CVE-2024-55591
  3. CISA KEV alert adding CVE-2024-55591
  4. Arctic Wolf follow-up on CVE-2024-55591
  5. Arctic Wolf Console Chaos campaign analysis
  6. watchTowr technical analysis
  7. Censys advisory and exposure data
  8. watchTowr detection script repository
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.