Abstract cutaway showing a red path bypassing a metal security patch to reach protected filesystem layers

CVE-2025-68686: The FortiOS Patch Bypass That Starts After Compromise

At 02:15, a SOC analyst notices repeated anonymous requests to an internet-facing FortiGate SSL-VPN. The appliance was patched for the vulnerability believed to have provided initial access months earlier. Authentication logs show no successful login, administrative accounts look unchanged, and the firmware inventory appears compliant. Nevertheless, the response sizes suggest that the remote client is retrieving data rather than merely scanning the service.

The first assumption is a new pre-authentication compromise. That interpretation is understandable and potentially wrong. The attacker may not be breaking in now. They may be using filesystem state planted during an earlier compromise to recover read-only access through a symbolic-link persistence mechanism that survived the first remediation effort.

That distinction is the key to CVE-2025-68686. This is a FortiOS SSL-VPN symbolic-link persistence patch bypass and post-exploitation information-disclosure vulnerability. It is not a standalone initial-access CVE. Treating it as an isolated patching problem risks preserving the compromise state that makes exploitation possible.

The problem: a post-exploitation primitive, not an entry point

The authoritative CVE record classifies CVE-2025-68686 as CWE-200, exposure of sensitive information to an unauthorized actor. A remote, unauthenticated attacker may use crafted HTTP requests to bypass a patch developed for a symbolic-link persistence mechanism observed in post-exploitation cases. Crucially, the attacker must first have compromised the product through another vulnerability and obtained filesystem-level access.

Fortinet advisory FG-IR-25-934 makes that dependency explicit. It also states that products that never had SSL-VPN enabled are not affected. “Disabled today” is not the same as “never enabled,” particularly when an appliance may have been exposed before an upgrade or configuration change.

A scanner finding an affected version identifies exposure, but not a complete path from an arbitrary internet client to filesystem compromise. Conversely, patching the original entry vulnerability does not prove that a device is clean if hostile filesystem state was created before patching.

The security model therefore has two stages:

  1. Initial compromise: an attacker exploits a different vulnerability and reaches the FortiOS filesystem.
  2. Persistent disclosure: the attacker uses filesystem state and crafted HTTP requests to bypass protection around the previously observed symbolic-link mechanism.

The second stage is where CVE-2025-68686 matters. The disclosed impact is information disclosure, not arbitrary command execution, configuration modification, or a new filesystem-write primitive. This distinction matters in attack-chain reconstruction and in any authorized validation report.

Affected versions and current remediation guidance

The structured CVE record lists these affected ranges:

  • FortiOS 7.6.0 through 7.6.1
  • FortiOS 7.4.0 through 7.4.6
  • FortiOS 7.2.0 through 7.2.13
  • FortiOS 7.0.0 through 7.0.19
  • FortiOS 6.4.0 through 6.4.16

The prose and the current Fortinet advisory describe the 7.2, 7.0, and 6.4 branches as affected in all versions. The operative vendor guidance is:

  • Upgrade FortiOS 7.6 to 7.6.2 or later.
  • Upgrade FortiOS 7.4 to 7.4.7 or later.
  • Migrate FortiOS 7.2, 7.0, and 6.4 deployments to a fixed release.

Do not reinterpret the upper bounds in the structured CVE data as proof of a fixed older-branch release. Use Fortinet’s Upgrade Path Tool to calculate the supported sequence for the exact appliance model and starting build.

The CVSS 3.1 score is 5.3 Medium:

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N/E:P/RL:O/RC:C

The network vector, absence of authentication, and high confidentiality impact are serious. The high attack complexity reflects the decisive prerequisite: the appliance must already contain attacker-created filesystem state.

Why the KEV timeline changes prioritization

Fortinet published the advisory on February 10, 2026 and updated it on March 12, 2026. That page still carried “Known Exploited: No” at its last update. On July 27, 2026, however, CISA added CVE-2025-68686 to the Known Exploited Vulnerabilities Catalog, with a remediation due date of August 10, 2026. CISA lists known ransomware use as Unknown, not “No.”

The defensible current wording is therefore precise: CISA now classifies the vulnerability as exploited in the wild; Fortinet’s older advisory field has not been publicly reconciled. The public sources do not identify the actor, victim count, exploitation dates, request format, or campaign relationship.

Technical deep dive: when pathname validation is not object validation

A symbolic link is a filesystem object that points to another path. Applications often validate the pathname presented to them, while the operating system resolves that name to a different final object. That indirection becomes dangerous when a network service assumes that every name beneath a public directory resolves to data physically contained inside that directory.

Consider a service intended to expose only files below a directory named public. A lexical check sees public/status.txt and approves it. If status.txt is a symbolic link to a sensitive file outside public, opening the approved name crosses the intended trust boundary. Robust handling must account for the canonical, fully resolved destination and race conditions around resolution, not merely the visible pathname.

Fortinet’s April 2025 threat-activity analysis gives the architecture-level context without publishing a vendor-specific exploit recipe. In the observed activity, an actor exploited known, unpatched FortiGate vulnerabilities and created a symbolic link connecting the user and root filesystems in a directory used to serve SSL-VPN language files. The user-filesystem modification could survive remediation of the initial vulnerability and preserve read-only access to device files, potentially including configuration data.

That 2025 analysis describes the original persistence technique. It does not document the later CVE-2025-68686 bypass implementation, and the two should not be collapsed into a fabricated exploit narrative.

Persistence does not require a running implant

Persistence is often visualized as a service, scheduled task, privileged account, or continuously running implant. Here, persistent capability can arise from durable data-plane state: a filesystem reference that causes a legitimate service to retrieve an unintended object. The attacker does not need a resident process if the trusted service keeps resolving hostile state on demand.

An upgrade is not automatically an eradication procedure

Firmware remediation can close the entry point while leaving attacker-created state elsewhere. Fortinet specifically described symbolic-link state that could remain after versions addressing the original vulnerabilities were installed. “Patched” and “not compromised” must therefore remain separate fields in the incident tracker.

This is the same operational mistake defenders encounter in other edge compromises: replacing vulnerable code without investigating state, credentials, and persistence. Our analysis of SharePoint exploitation in 2026 follows the same patch-hunt-harden sequence, while the shared-hosting web-shell hunt shows why eradication must be evidence-driven rather than file-driven.

Unauthenticated does not mean prerequisite-free

The CVSS privileges-required metric is PR:N because the eventual HTTP request needs no authenticated FortiOS session. That does not erase the environmental prerequisite. Someone must previously have obtained enough filesystem access through another vulnerability to establish the exploitable condition.

Security leaders should resist translating AV:N/PR:N into “any internet user can compromise a FortiGate with this CVE.” Equally, defenders should not downgrade the issue because prior compromise is required. A successful retrieval would imply that the organization has both a disclosure path and an earlier, deeper incident to reconstruct.

A realistic attack chain

  1. Exposure: a FortiGate has SSL-VPN enabled and is reachable from an untrusted network.
  2. Initial compromise: the actor exploits a separate vulnerability. This is the actual initial-access event; CVE-2025-68686 does not provide it.
  3. Filesystem manipulation: while the earlier access remains available, the actor establishes symbolic-link state capable of connecting SSL-VPN-served content to files outside the intended boundary.
  4. Partial remediation: the organization patches the original vulnerability but performs no compromise assessment, state validation, credential rotation, or trusted recovery.
  5. Patch-bypass request: the actor sends crafted HTTP requests that exercise CVE-2025-68686 and bypass protection developed for the observed persistence mechanism.
  6. Information disclosure: the actor recovers read-only access to sensitive filesystem content, potentially including configuration data.
  7. Follow-on operations: exposed information may improve later targeting, but credential abuse, lateral movement, or renewed write access would be separate activity requiring separate evidence.

For a red team, this chain is a reminder to distinguish exploitability from precondition construction. An internet-only assessment without prior authorized filesystem control cannot honestly claim end-to-end exploitation of this CVE. For defenders, the dependency raises rather than lowers incident urgency: the second stage points back to an initial compromise that may have gone undetected.

Six-stage diagram separating prior FortiOS compromise and symlink state from the CVE-2025-68686 HTTP disclosure path
The initial foothold and filesystem manipulation are preconditions; CVE-2025-68686 is the later disclosure path.

Safe lab: reproducing the symlink-following mechanism

This self-contained lab demonstrates a generic filesystem mechanism with Python’s standard library. It is not a FortiOS exploit, does not reproduce Fortinet request handling, and contains no vendor-specific endpoint, path, or crafted request. Primary sources have not disclosed those details.

The fictional hostname fortigate.lab.example is mapped to 127.0.0.1:8088 per request with curl’s --resolve. First, create an isolated public tree, a fictional device configuration, and a symbolic link from the public directory to the private file:

rm -rf /tmp/symlink-lab
mkdir -p /tmp/symlink-lab/public /tmp/symlink-lab/private

cat > /tmp/symlink-lab/private/device.conf <<'EOF'
hostname=fictional-gateway
[email protected]
vpn_mode=lab-only
demo_secret=NOT-A-REAL-SECRET
EOF

printf 'public health check: ok\n' > /tmp/symlink-lab/public/health.txt
ln -s ../private/device.conf /tmp/symlink-lab/public/config.txt

ls -l /tmp/symlink-lab/public
readlink /tmp/symlink-lab/public/config.txt

Start a generic static file server bound only to loopback:

cd /tmp/symlink-lab/public
python3 -m http.server 8088 --bind 127.0.0.1

Keep that terminal open. From a second terminal, request the expected public file and then the linked name through the fictional host mapping:

curl --noproxy '*' \
  --resolve fortigate.lab.example:8088:127.0.0.1 \
  http://fortigate.lab.example:8088/health.txt

curl --noproxy '*' -i \
  --resolve fortigate.lab.example:8088:127.0.0.1 \
  http://fortigate.lab.example:8088/config.txt

The first response contains only the health message. The second demonstrates the boundary failure by returning the fictional configuration through a name located inside public. Confirm the resolution chain locally:

namei -l /tmp/symlink-lab/public/config.txt
realpath /tmp/symlink-lab/public/config.txt

Stop the server with Ctrl-C. Now create a defensive server that resolves the requested object and refuses destinations outside the approved document root:

cat > /tmp/symlink-lab/fixed_server.py <<'PY'
from http.server import ThreadingHTTPServer, SimpleHTTPRequestHandler
from pathlib import Path
from urllib.parse import unquote, urlsplit

ROOT = Path("/tmp/symlink-lab/public").resolve()

class SafeHandler(SimpleHTTPRequestHandler):
    def translate_path(self, path):
        request_path = unquote(urlsplit(path).path).lstrip("/")
        candidate = (ROOT / request_path).resolve()
        try:
            candidate.relative_to(ROOT)
        except ValueError:
            return str(ROOT / "__blocked__")
        return str(candidate)

ThreadingHTTPServer(("127.0.0.1", 8088), SafeHandler).serve_forever()
PY

python3 /tmp/symlink-lab/fixed_server.py

Repeat the requests:

curl --noproxy '*' -i \
  --resolve fortigate.lab.example:8088:127.0.0.1 \
  http://fortigate.lab.example:8088/health.txt

curl --noproxy '*' -i \
  --resolve fortigate.lab.example:8088:127.0.0.1 \
  http://fortigate.lab.example:8088/config.txt

The public file still returns successfully. The symlink resolving outside /tmp/symlink-lab/public no longer discloses device.conf. Stop the process and clean up:

rm -rf /tmp/symlink-lab

The lesson is not that FortiOS uses Python or behaves exactly like this server. The lab isolates one security property: checking an apparent public name is insufficient if the final resolved object crosses a trust boundary. It deliberately does not speculate about Fortinet’s undisclosed implementation.

Detection and incident-response priorities

Scope by history, not only current state

Inventory every FortiGate, exact FortiOS build, external exposure, owner, and whether SSL-VPN has ever been enabled. Fortinet says products that never had SSL-VPN enabled are not impacted. Current service state alone may be insufficient for scoping.

External discovery can validate perimeter inventory, but it is not proof of exploitability. The distinction between exposure evidence and exploit evidence is covered in our Shodan guide for offensive security.

Separate patching from compromise assessment

  • Preserve relevant logs, configuration backups, upgrade history, and available appliance telemetry before destructive recovery.
  • Determine whether the device was internet-exposed while known FortiGate vulnerabilities remained unpatched.
  • Review unexplained anonymous SSL-VPN requests, unusual response volumes, repeated retrieval patterns, and activity inconsistent with normal portal use.
  • Use Fortinet-supported diagnostics and incident-response procedures to examine suspected filesystem persistence. Do not rely on invented path lists or unsupported shell commands.
  • Compare the running configuration with a trusted baseline and treat configuration data as potentially exposed when compromise is credible.
  • Rotate credentials, keys, certificates, and downstream secrets whose exposure is supported by the investigation.
  • Where integrity cannot be established, recover from a trusted state under vendor guidance rather than assuming that deleting one artifact is sufficient.

CISA’s KEV inclusion should override a queue sorted only by CVSS. Asset exposure, prior vulnerability history, SSL-VPN use, and the possibility of persistent hostile state make this medium-scored issue operationally urgent. Fortinet also lists virtual patch FG-VD-60389.0day in FMWP database update 26.033, but the advisory’s solution remains upgrade or migration; a virtual patch should not be treated as evidence that a previously compromised appliance is clean.

What the public record does not tell us

Technical accuracy requires an explicit boundary around unknowns. As of July 29, 2026, the cited primary sources do not disclose:

  • The crafted HTTP request, endpoint, parameters, or a reproducible public PoC.
  • The exact implementation error that makes the patch bypass possible.
  • A mandatory initial-access CVE.
  • Bypass-specific paths, filenames, hashes, IP addresses, domains, or log signatures.
  • The exploiting actor, victim count, campaign, or exploitation start date.
  • Confirmed ransomware involvement; CISA’s value is “Unknown.”
  • Direct RCE, integrity impact, or availability impact attributable to this CVE.

The 2025 Fortinet post named older vulnerabilities associated with the original activity, but CVE-2025-68686 only requires compromise through “another vulnerability.” Likewise, the 2025 post’s cleanup releases must not be presented as fixes for this later bypass. The 2026 advisory supersedes that assumption for this CVE.

Strategic takeaways

  • Do not misclassify the CVE. It is a post-exploitation information-disclosure and symbolic-link persistence patch bypass, not initial access.
  • Do not confuse unauthenticated retrieval with prerequisite-free exploitation. The HTTP request may need no login while the filesystem condition depends on earlier attacker access.
  • Patch and eradicate are different verbs. Closing an initial vulnerability does not necessarily remove state created while it was exploitable.
  • Feature history matters. “SSL-VPN disabled” and “SSL-VPN never enabled” are different scoping facts.
  • Use current guidance. Upgrade 7.6 to 7.6.2 or later, upgrade 7.4 to 7.4.7 or later, and migrate affected older branches through a supported path.
  • Prioritize observed exploitation. CISA’s July 27 KEV listing is the current operational signal; ransomware use remains unknown.
  • Avoid fictional precision. A mechanism lab can be useful without inventing Fortinet-specific request syntax, paths, IoCs, or root-cause details.

The broader lesson extends beyond FortiOS. Edge appliances are stateful systems, not disposable version numbers. When attackers gain filesystem access, remediation must account for what they changed, what survived an upgrade, and which trusted services can later expose that state. CVE-2025-68686 is medium by score, conditional by design, and still urgent because exploitation is now documented in CISA KEV. Patch it—but investigate the compromise that had to come first.

💜 Enjoyed this content? Support the blog with USDT (TRC20):

TX7obcjHQbDUXb4mGqoASEu1QFTKT2CFGG

View support page

Paulo Rigonato

Security Engineer | Red Team | Pentest

Offensive security specialist with experience in assessments, pentesting, and Red Team operations. He works in enterprise cybersecurity and continues to share knowledge through this blog.

Certifications: OSCP | eWPTXv2 | ITILv4

💻 GitHub 🔗 LinkedIn

Similar Posts