top of page

Hunt FortiBleed: the firewall admin you didn't create

Writer: Inception Security
Inception Security
8 minutes ago
8 min read

The firewall admin signs in on a Monday and the password is wrong. It worked on Friday. The admin list now holds an account called something like forticloud-sync that nobody remembers creating. Someone knew a password that still worked.

On 6 October 2026, the FBI and the US Secret Service published joint advisory JCSA-20261006-01 on FortiBleed, "an active, global credential-compromise campaign" against internet-facing FortiGate firewalls and SSL VPN gateways. SOCRadar, cited by the FBI, verified more than 86,644 compromised devices across 194 countries. The new part is the ending: affected organizations "may find themselves locked out of their systems," which requires "remediation steps beyond standard patching and password resets," and the chain has served as "an initial entry point for ransomware affiliates."

Why this one is different

FortiBleed is not a CVE. In June, Fortinet said "this is not a new Fortinet vulnerability," tying the activity to credentials reused from FG-IR-26-060 and FG-IR-25-647 plus brute force against devices with weak passwords and no MFA. CISA warned on 18 June. This week the FBI says scanning continues "using previously obtained compromised credentials," now with reports of lockouts.

A firmware upgrade does not remove an admin someone else created, and a reset does not help if your account is already gone.

The attacker logged in with a real password, so the alert you need is the account that should not exist.

Ask yourself two questions. Could you name who created every admin on every FortiGate today? And if a VPN address failed logins against dozens of domain accounts in an hour, would anyone notice?

How a leaked password becomes a locked-out firewall

The FBI traced the full chain from a leaked password to a locked-out firewall. Here is how it works, in three stages.


From leak dump to a valid login

The FBI says the workflow became visible "only after the threat actors unintentionally exposed their own backend server." The operators scanned for exposed FortiGate SSL VPN portals, then ran credential stuffing and password spraying "based on prior Fortinet leak dumps and infostealer logs." Hashes dumped from compromised devices went to a rented GPU cluster for offline cracking. Working credentials were validated and targets ranked "based on revenue and network structure."

From admin to owner

Once in, the operators "created new administrative accounts on FortiGate devices to maintain persistent access." In certain cases they also deleted existing accounts "to block organizations from accessing affected devices." The FBI adds that they "may have exploited SSH if the port was open on the firewall."

Our reading: a firewall admin controls VPN policy, routing, and logging, so the first thing an intruder can take away is your visibility into what they are doing.

From the firewall to the domain, then to a buyer

Inside, the operators ran Active Directory enumeration and password spraying to find privileged accounts. The FBI says the operation ended in "packaging and selling access," and that initial access brokers using the chain have supplied ransomware affiliates, "currently including INC/Lynx ransomware and Payload ransomware."

What the FBI published and what it did not

The FBI published the chain above, ATT&CK mappings (MITRE's catalog of attacker techniques) including Account Access Removal (T1531) and Local Account Creation (T1136.001), and network indicators: a command-and-control (C2) server at 45[.]154[.]12[.]132, a beacon relay at 45[.]155.]250[.]158, two proxy nodes, and three supporting addresses, one used for Hashtopolis (a distributed password-cracking tool). The actors use ports including 4332 and 4432, "but usually beaconing to" HTTPS. Table 1 lists 13 addresses seen brute-forcing or authenticating between 18 June and 23 July 2026, and Table 2 lists 19 account names found on victim devices. Fortinet's own examples add forticloud, fortiuser, fortinet-support, and fortinet-tech-support.

It did not publish victim names, a count of lockouts, sectors, the broker's name, or file hashes. It warns that Table 1 addresses "may later be reassigned to benign services" and says to vet indicators "prior to acting, such as blocking."

What to change this week

If the hunts below find a hit, follow the FBI's order: isolate, scope, report to the FBI or USSS, then evict. Fortinet says to treat a device with unapproved configuration changes as compromised, along with any AD or LDAP account it uses. Whether or not you find a hit, do these in order:

  1. Terminate all active admin and VPN sessions. A reset does nothing to an open session.

  2. Reset all VPN and admin passwords and require phishing-resistant MFA on every admin and remote access account.

  3. Compare each configuration to a known good copy and remove any account you did not create.

  4. Review every REST API key, remove unknown ones, and refresh the rest, as the FBI avises.

Then take management off the internet: trusted hosts are good, a local-in policy is better, no internet administration is best. Our reading: treat old config backups as

credential material, since dumped hashes fed this campaign.


Four hunts to run (test first)

The FBI says to review firewall, VPN, authentication, and domain controller logs and verify every Fortinet account. Each query is our translation into field names, so test each one first. The hunts skip admin from Table 2 because it is the FortiGate default; count it only if it was created recently. Set the window back to at least 18 June. The table under the hunts, "Interpret before you escalate", says what is benign and what is not.

Hunt in Splunk: admin changes, named accounts, and FBI addresses (test first)

index=YOUR_FORTIGATE_INDEX type=event (subtype=system OR subtype=vpn) earliest=-120d
| eval src=coalesce(srcip, remip), acct=lower(coalesce(cfgobj, user)), act=coalesce(vendor_action, action)
| eval signals=mvappend(
    if(cfgpath="system.admin" AND match(act, "(?i)^(add|delete|edit)$"), "admin_object_change", null()),
    if(match(logdesc, "(?i)admin login successful") AND match(ui, "(?i)^ssh"), "admin_ssh_login", null()),
    if(in(acct, "adminin","fortiadmin","forticloud-sync","fgtsecure","pakedge","forticloud-tech","districtadmin","system_config","gttadmin","roadmin","itadmin","technical_support","adminsslvpn","it_manager","my_admin","support_fortinet","fgtsec","forti_support2","forticloud","fortiuser","fortinet-support","fortinet-tech-support"), "named_account", null()),
    if(in(src, "104.28.155.27","185.136.15.43","185.136.15.66","185.199.199.56","193.8.186.33","45.227.254.210","77.91.118.10","80.75.212.113","87.251.64.13","87.251.64.16","87.251.64.17","87.251.64.44","66.175.220.111","45.154.12.132","154.202.59.169","103.27.186.156","45.155.250.158","193.8.187.2","193.8.187.42","85.11.187.8"), "fbi_ip", null()))
| where isnotnull(signals)
| stats min(_time) as first_seen, max(_time) as last_seen, values(signals) as signals, values(act) as actions, values(src) as sources, values(ui) as ui by devname, acct
| convert ctime(first_seen) ctime(last_seen)
| sort 0 first_seen

Field mapping: FortiGate syslog via the Fortinet add-on. Admin changes are log ID 44547 and carry cfgpath, cfgobj, and action; SSL VPN events put the remote address in remip. The add-on keeps the raw action in vendor_action, so the query reads that first. Rename if your sourcetype differs. Test first.

False positives: planned admin changes; MSP or installer accounts named like itadmin or IT_Manager. Edit covers password changes and routine edits alike; a password change shows password[*] in cfgattr.

Empty result: confirm config change events are forwarded, not just traffic. Our reading: an unexplained named_account plus Add is worth a call on its own.

Hunt in Kibana: rogue admins, then the failure burst that turned into a session (test first)

Search 1: rogue admins, named accounts, and FBI addresses

(fortinet.firewall.cfgpath : "system.admin" and fortinet.firewall.action : ("Add" or "Delete" or "Edit"))
or user.name : ("adminin" or "fortiAdmin" or "forticloud-sync" or "fgtsecure" or "pakedge" or "forticloud-tech" or "districtadmin" or "system_config" or "gttadmin" or "roadmin" or "itadmin" or "Technical_support" or "adminsslvpn" or "IT_Manager" or "my_admin" or "support_fortinet" or "fgtsec" or "forti_support2" or "forticloud" or "fortiuser" or "fortinet-support" or "fortinet-tech-support")
or source.ip : (104.28.155.27 or 185.136.15.43 or 185.136.15.66 or 185.199.199.56 or 193.8.186.33 or 45.227.254.210 or 77.91.118.10 or 80.75.212.113 or 87.251.64.13 or 87.251.64.16 or 87.251.64.17 or 87.251.64.44 or 66.175.220.111 or 154.202.59.169 or 103.27.186.156 or 193.8.187.2 or 193.8.187.42 or 85.11.187.8)
or destination.ip : (45.154.12.132 or 45.155.250.158)

Search 2: a failure burst that becomes a tunnel

sequence by source.ip with maxspan=1h
  [any where observer.vendor == "Fortinet" and fortinet.firewall.action == "ssl-login-fail"] with runs=10
  [any where observer.vendor == "Fortinet" and fortinet.firewall.action == "tunnel-up"]

Field mapping: KQL in Discover over the Elastic Fortinet integration, then EQL in Timelines. The integration keeps FortiGate event actions in fortinet.firewall.action and moves the SSL VPN remip into source.ip. Group by observer.name and user.name. Test first.

False positives: a user who forgot a password and then got it right; a scanner you own.

Empty result: confirm the integration ships event logs and keeps fortinet.firewall.cfgpath.

Hunt in Falcon CQL: admin changes, then spraying from the VPN pool (test first)

Search 1: admin changes, named accounts, and FBI addresses on the FortiGate

#Vendor="fortinet"
| coalesce([source.ip, Vendor.remip], as=client_ip)
| case {
    @rawstring=/cfgpath="?system\.admin/i @rawstring=/action="?(Add|Delete|Edit)\b/i | signal := "admin_object_change" ;
    @rawstring=/(user|cfgobj)="?(adminin|fortiAdmin|forticloud-sync|fgtsecure|pakedge|forticloud-tech|districtadmin|system_config|gttadmin|roadmin|itadmin|Technical_support|adminsslvpn|IT_Manager|my_admin|support_fortinet|fgtsec|forti_support2|forticloud|fortiuser|fortinet-support|fortinet-tech-support)"?(\s|$)/i | signal := "named_account" ;
    in(field="client_ip", values=["104.28.155.27","185.136.15.43","185.136.15.66","185.199.199.56","193.8.186.33","45.227.254.210","77.91.118.10","80.75.212.113","87.251.64.13","87.251.64.16","87.251.64.17","87.251.64.44","66.175.220.111","154.202.59.169","103.27.186.156","193.8.187.2","193.8.187.42","85.11.187.8"]) | signal := "fbi_ip" ;
    in(field="destination.ip", values=["45.154.12.132","45.155.250.158"]) | signal := "c2_or_relay" ;
    * | signal := "" ;
  }
| signal != ""
| regex("devname=\"?(?<devname>[^\"\s]+)", field=@rawstring, strict=false)
| groupBy([devname, signal], function=[min(@timestamp, as=first_seen), count()])
| sort(first_seen, order=asc)

Search 2: domain logon failures fanning out from the VPN pool

#event_simpleName=UserLogonFailed2
| cidr(RemoteAddressIP4, subnet="YOUR_SSL_VPN_POOL/24")
| bucket(span=1h, field=[RemoteAddressIP4], function=[count(UserName, distinct=true, as=accounts), count(as=failures)])
| accounts >= 15

Field mapping: Falcon Next-Gen SIEM with the FortiGate parser, then sensor data from domain controllers. The parser files the SSL VPN remip under destination.ip, so the query reads Vendor.remip too. Set your SSL VPN pool and tune the threshold. Test first.

False positives: a misconfigured service retrying from a VPN user's laptop; a sanctioned scanner.

Empty result: confirm the parser fills source.ip or Vendor.remip and that Kerberos failures reach the platform.

Hunt in KQL: Fortinet CEF plus domain controller fan-out (test first)

let Window = ago(120d);
let FbiIps = dynamic(["104.28.155.27","185.136.15.43","185.136.15.66","185.199.199.56","193.8.186.33","45.227.254.210","77.91.118.10","80.75.212.113","87.251.64.13","87.251.64.16","87.251.64.17","87.251.64.44","66.175.220.111","154.202.59.169","103.27.186.156","193.8.187.2","193.8.187.42","85.11.187.8"]);
let C2 = dynamic(["45.154.12.132","45.155.250.158"]);
let Names = dynamic(["adminin","fortiadmin","forticloud-sync","fgtsecure","pakedge","forticloud-tech","districtadmin","system_config","gttadmin","roadmin","itadmin","technical_support","adminsslvpn","it_manager","my_admin","support_fortinet","fgtsec","forti_support2","forticloud","fortiuser","fortinet-support","fortinet-tech-support"]);
let VpnPool = "YOUR_SSL_VPN_POOL/24";
let Fgt = CommonSecurityLog
| where TimeGenerated >= Window
| where DeviceVendor == "Fortinet"
| extend CfgObj = tolower(extract(@"FTNTFGTcfgobj=([^;\s]+)", 1, AdditionalExtensions))
| extend Acct = tolower(coalesce(CfgObj, SourceUserName, DestinationUserName))
| extend Src = coalesce(SourceIP, extract(@"FTNTFGTremip=([^;\s]+)", 1, AdditionalExtensions))
| extend Device = coalesce(DeviceName, DeviceExternalID, Computer)
| extend Signal = case(
    AdditionalExtensions has "system.admin" and DeviceAction in~ ("Add", "Delete", "Edit"), "admin_object_change",
    Acct in (Names), "named_account",
    Src in (FbiIps), "fbi_ip",
    DestinationIP in (C2) or DestinationPort in (4332, 4432), "c2_or_beacon_port",
    "")
| where Signal != ""
| summarize FirstSeen = min(TimeGenerated), Signals = make_set(Signal), Accounts = make_set(Acct, 20) by Device;
let Spray = SecurityEvent
| where TimeGenerated >= Window
| where EventID in (4625, 4771)
| extend Src = trim_start(@"::ffff:", IpAddress)
| where ipv4_is_in_range(Src, VpnPool)
| summarize Accounts = make_set(TargetUserName, 20), Distinct = dcount(TargetUserName), FirstSeen = min(TimeGenerated) by Src, bin(TimeGenerated, 1h)
| where Distinct >= 15
| project FirstSeen, Device = Src, Signals = dynamic(["vpn_pool_ad_fanout"]), Accounts;
union Fgt, Spray
| order by FirstSeen asc

Field mapping: Sentinel with Fortinet CEF in CommonSecurityLog and domain controller Security events. FortiOS sends user as duser, action as act, and unmapped fields such as cfgobj and remip with an FTNTFGT prefix, so check one admin change first. Test first.

False positives: legitimate services on 4332 or 4432 match the port clause alone; only the two FBI addresses are specific.

Empty result: confirm the firewall's own outbound traffic is logged, and that 4771 is audited on domain controllers.

Interpret before you escalate

Finding

Benign read

Escalate when

Admin added on system.admin

Planned change

No change record, or the creator is itself new

Original admin deleted or re-passworded

Offboarding or rotation

A new admin appeared the same day

Table 2 or Fortinet example account

Documented MSP account

Nobody knows who created it

Login from an FBI listed address

Address reassigned since July

Successful login between 18 June and 23 July 2026

Firewall traffic to the C2 or relay

None we know of

Always; treat the device as compromised

SSL VPN failure burst, then a tunnel

Forgotten password

Domain failures fan out from that tunnel address

VPN pool address failing on many accounts

Misconfigured service

Many distinct accounts in an hour

Empty results

Nothing matched

Config, VPN, or DC logs are missing or retention stops short of June, so fix coverage first

Sources

What This Means for Your Team

Stop treating this as a patch window. Kill sessions, reset, and turn on MFA, then pull the admin list from every FortiGate and make someone sign their name next to each account. Run the four hunts back to 18 June. An admin nobody created is the seam to chase, and a VPN address spraying your domain controllers means the firewall was only the front door.

Inception Protection

Inception Protection is our managed detection and response service, and it works with the Microsoft licenses you already have. A chain like this starts on the firewall and ends in Active Directory, so we read firewall logs next to Defender, Entra sign-in, and domain controller signals as one story and move on accounts fast. You keep the decisions.

Inception Foresight

If you want to see how well your Microsoft environment would surface activity like this, the free Inception Foresight M365 Assessment is a good place to start: https://www.inceptionsecurity.com/m365assessment. You can also follow Inception Security on LinkedIn and @inceptionsec on X.

bg-map-white.png

INCEPTION SECURITY™

A cybersecurity company with in depth knowledge of the threat landscape and security controls.

NAVIGATION

GET IN TOUCH

© 2025 All Rights Reserved by INCEPTION SECURITY™ .

bottom of page