Port 27918 Takes gRPC With No Client Certificate: Horizon3 Turns FortiSIEM CVE-2026-106173 Into Unauthenticated RCE
On 13 October 2026 Fortinet published advisory FG-IR-26-180 for CVE-2026-106173, a critical path traversal (CWE-22) in FortiSIEM rated CVSSv3 9.4, unauthenticated, allowing execution of unauthorised code or commands via specially crafted packets. Only FortiSIEM 7.5 (version 7.5.0) is affected; 7.6 was never vulnerable, the fix is 7.5.1 or above, FortiSIEM Cloud is not affected, and Fortinet lists no known exploitation. Seven days later, on 20 October, Horizon3’s Zach Hanley published a full deep-dive with a public proof of concept — and the details make this one of the more instructive unauthenticated-RCE chains of the month. We read both documents first-hand.
A new service nobody had looked at
Horizon3 is unusually well qualified on this target: the team previously disclosed CVE-2023-34992, CVE-2024-23108 and CVE-2025-64155 against FortiSIEM, and every one of those went through the same component, the phMonitor service on tcp/7900. This advisory pointed somewhere new — a gRPC service, phQueryMaster, on tcp/27918 — and the first finding sets the tone for everything after it. The service builds its listen address as [::]:27918, binding every interface, and sets the gRPC client-certificate option to do-not-request. Any remote client can connect unauthenticated, with no client certificate, and reach the vulnerable handler. The authentication boundary here is not broken; it was never erected.
The handler is SendQueryResult, which takes four values from the request — a query-id, a source IP, and a period start and end — plus a stream of file-content bytes. It builds the destination path by string concatenation: a directory from the query-id, a filename from the source IP and the period values. There is, in Horizon3’s telling, no input validation anywhere in that construction.
Traversal plus a null byte equals an exact-path write
The exploit has two stages, and the second is the elegant one. First, a query-id of ../../../../../tmp/x escapes the query directory — ordinary traversal, giving arbitrary directory control but not an exact filename, because the server always appends its own result-<src>-<start>-<end>-<id>.dat suffix with a server-controlled counter. On its own that is a constrained write. Then comes the observation that the server copies the header values using the client-declared length, so an attacker can embed a null byte mid-value: a query-id of .../some/target followed by a null byte and junk. When the path reaches the operating system, the OS treats the null byte as end-of-string and silently discards everything after it — including the server’s own suffix. The write lands on exactly the path the attacker chose.
Pointed at an existing file, a single request overwrites it in place, keeping the original owner and permissions; a two-request variant creates a brand-new file with an exact name. Normal tooling cannot do this — curl and standard gRPC libraries refuse null bytes in headers — so Horizon3 hand-assembles the gRPC message. That implementation detail is a speed bump for script kiddies and no obstacle at all to anyone who reads the PoC, which is now public on the company’s GitHub.
From file write to code execution in sixty seconds
Arbitrary file write becomes RCE the usual way: by finding a file the system executes. FortiSIEM runs many services that ingest files through cron jobs, and one health-check script for the Redis service, /opt/charting/redishb.sh, executes every 60 seconds and is writable in the attacker’s reachable context. Overwrite it, wait a minute. The full chain is therefore: one unauthenticated gRPC request with a crafted query-id, one minute of patience, and the SIEM — the box that watches everything else — runs your script on schedule.
Horizon3 is candid about the defensive gap that follows: it found no application logs that would explicitly reveal exploitation. Detection is forensic, not telemetry-driven — inspect file write and modification timestamps for anything inconsistent with surrounding files, with redishb.sh and /opt/phoenix/bin/phLicenseTool named as files of particular interest. A SIEM that cannot log its own compromise through the vulnerable service is a reminder that the monitoring plane needs its own monitoring, from outside itself.
What to do, in order
- Patch to FortiSIEM 7.5.1 or above. Only 7.5.0 is affected; 7.6 and Cloud need no action. If your asset inventory cannot answer “which of our FortiSIEMs are 7.5.0” in minutes, that is the first thing to fix.
- If you cannot patch, restrict tcp/27918 now. This is Fortinet’s own workaround, and it is structurally sound: the vulnerable service is unreachable if the port is unreachable. Firewall the port at every boundary, including east-west, because the attacker only needs to reach it from anywhere the SIEM’s management network is visible.
- Hunt backwards, not just forwards. Fortinet’s advisory says exploitation is not known, and a public PoC dated 20 October resets the meaning of that statement. Pull mtimes on the two named files and any cron-executed script writable outside root’s control across every 7.5.0 host, including ones already upgraded — exploitation may predate the patch.
- Treat the SIEM as a high-value target in the threat model. This is the fourth Horizon3 RCE chain against the same product line, and the second component to fall. Compromise of the watcher blinds the watched; FortiSIEM instances deserve the same exposure discipline as domain controllers and backup servers.
The broader pattern is worth naming alongside this week’s FortiMail path-traversal-to-file-write chain: Fortinet’s Java and C++ services keep building filesystem paths out of network input by concatenation, and researchers keep turning that into code execution through scheduled tasks. The vulnerability class is CWE-22, one of the oldest entries in the catalogue. The novelty each time is only the address and the port number. Until path construction from remote input is treated as guilty until proven innocent across the product line, the next advisory in this genre is a matter of scheduling.
Our verification was read-only. The CVE identifier, CVSSv3 9.4 score, critical severity, unauthenticated attack type, CWE-22 classification, 13 October 2026 publication date, affected version (7.5/7.5.0), fix version (7.5.1+), 7.6 and Cloud exclusions, tcp/27918 workaround and internal-discovery credit were read first-hand from Fortinet advisory FG-IR-26-180. The gRPC service details, handler behaviour, traversal and null-byte technique, cron-executed script path and 60-second interval, public-PoC statement, absent-logging finding and forensic file list were read first-hand from Horizon3’s 20 October 2026 deep-dive by Zach Hanley. No FortiSIEM instance was probed, no exploit was run, and no exploit code is reproduced. Brave Search was used for discovery only.
Sources:
- Fortinet PSIRT — FG-IR-26-180, CVE-2026-106173 (13 October 2026)
- Horizon3 Attack Research — CVE-2026-106173 Deep-Dive: FortiSIEM gRPC Path Traversal File Write RCE (Zach Hanley, 20 October 2026)
- al-ice.ai — No Login, One Request, Any File: FortiMail 9.8 Path-Traversal Zero-Day Was Already Being Exploited