Rejetto HFS CVE-2026-61500 Active Exploitation Hunt

Threat Overview

Rejetto HTTP File Server (HFS) versions 3.0.0 through 3.2.0 use JavaScript Math.random() both to derive the Koa session-cookie signing key at process startup and to generate values returned during the unauthenticated SRP login handshake. Because V8’s xorshift128+ output is reversible, a remote attacker can gather several consecutive exposed values, reconstruct the PRNG state, recover the signing key, and mint a valid administrator session. HFS’s documented server_code configuration capability then provides a route from forged administrative access to server-side JavaScript and operating-system command execution.

The vulnerability is CVE-2026-61500 (CVSS 9.3). Rejetto released version 3.2.1 in July 2026, and a public Python proof of concept appeared in late September. VulnCheck reported exploitation attempts beginning October 1 against real vulnerable hosts in the United States, attributed only to an unnamed actor operating from China. No authoritative source in the references published durable attacker IPs, hashes, or a complete request signature; this package therefore prioritizes login-handshake bursts and post-exploitation process, file, persistence, and network behavior.

References

Impacted Systems

  • Vendor/product/component: Rejetto HTTP File Server (HFS) 3.x; session signing, SRP login, administrative API, and server_code functionality.
  • Affected versions: 3.0.0 through 3.2.0.
  • Fixed version: 3.2.1 or later.
  • Platform/deployment: Self-hosted HFS, normally Windows-based and frequently Internet-facing as a file-sharing/web service.
  • Server role: HFS application process and the Windows host account under which it runs.
  • Prerequisites: Network access to HFS and a valid login-enabled username; the cited research states that a password is not required to reach the vulnerable loginSrp1 stage.
  • Exposure: Highest for directly Internet-facing HFS listeners. Reverse-proxy exposure remains exploitable if the login and administrative paths are passed through.
  • Unaffected: HFS 3.2.1 and later are outside the published affected range; HFS 2.x is not identified as affected by this CVE.

Why this matters

Public exploit code and observed targeting compress the interval between disclosure and compromise. Successful exploitation yields HFS administrative control without valid credentials and can immediately become command execution under the HFS service identity. HFS is also often deployed outside conventional enterprise application inventories, making version discovery and behavioral confirmation equally important.

Exploitation Status

Active exploitation attempts are confirmed by VulnCheck. Attempts were detected beginning October 1, 2026, after public technical detail and proof-of-concept code became available. Public sources do not establish successful compromise counts or a stable set of attacker-controlled indicators. Behavior associated with harvesting SRP responses is necessary to the published technique, but a forged cookie may look syntactically valid and may not generate a failed-login event.

What this hunt looks for

HFS processes and versions, repeated loginSrp1 activity, administrative or server-code requests following handshake probes, HFS-spawned command interpreters, suspicious file writes, persistence changes, new outbound destinations, and Windows process-event fallback activity.

Required logs

Microsoft Defender for Endpoint DeviceProcessEvents, DeviceFileEvents, DeviceRegistryEvents, and DeviceNetworkEvents; reverse-proxy, WAF, or HTTP telemetry in CommonSecurityLog or AzureDiagnostics; and Windows Security Event 4688 with command-line auditing as a fallback.

Hunt 1 — First-pass HFS process and version inventory

let lookback = 14d;
DeviceProcessEvents
| where Timestamp >= ago(lookback)
| where FileName in~ ("hfs.exe", "hfs2.exe") or ProcessVersionInfoProductName has "HTTP File Server" or ProcessCommandLine has_any ("rejetto", " hfs ")
| summarize FirstSeen=min(Timestamp), LastSeen=max(Timestamp), Versions=make_set(ProcessVersionInfoProductVersion, 10), Paths=make_set(FolderPath, 10), Commands=make_set(ProcessCommandLine, 10) by DeviceName, FileName, SHA256
| order by LastSeen desc

Hunt 2 — Repeated unauthenticated SRP handshake activity

let lookback = 14d;
union isfuzzy=true CommonSecurityLog, AzureDiagnostics
| where TimeGenerated >= ago(lookback)
| extend Raw=tostring(pack_all()), Src=coalesce(column_ifexists("SourceIP", ""), column_ifexists("clientIp_s", ""), column_ifexists("CallerIPAddress", ""))
| where Raw has "loginSrp1"
| summarize Requests=count(), FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), Samples=make_set(substring(Raw, 0, 500), 3) by Src, bin(TimeGenerated, 5m)
| where Requests >= 3
| order by Requests desc

Hunt 3 — SRP probing followed by HFS administrative or server-code activity

let lookback = 14d;
let Http = union isfuzzy=true CommonSecurityLog, AzureDiagnostics
| where TimeGenerated >= ago(lookback)
| extend Raw=tostring(pack_all()), Src=coalesce(column_ifexists("SourceIP", ""), column_ifexists("clientIp_s", ""), column_ifexists("CallerIPAddress", ""));
let Probes = Http | where Raw has "loginSrp1" | summarize ProbeTime=min(TimeGenerated) by Src;
Http
| where Raw has_any ("server_code", "api.set_config", "admin")
| join kind=inner Probes on Src
| where TimeGenerated between (ProbeTime .. ProbeTime + 1h)
| project TimeGenerated, Src, ProbeTime, Raw=substring(Raw, 0, 1200)
| order by TimeGenerated desc

Hunt 4 — HFS spawning shells or dual-use utilities

let lookback = 30d;
DeviceProcessEvents
| where Timestamp >= ago(lookback)
| where InitiatingProcessFileName in~ ("hfs.exe", "hfs2.exe") or InitiatingProcessVersionInfoProductName has "HTTP File Server"
| where FileName in~ ("cmd.exe", "powershell.exe", "pwsh.exe", "wscript.exe", "cscript.exe", "mshta.exe", "rundll32.exe", "regsvr32.exe", "certutil.exe", "curl.exe", "bitsadmin.exe")
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine, SHA256, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessSHA256
| order by Timestamp desc

Hunt 5 — Suspicious files created by HFS

let lookback = 30d;
DeviceFileEvents
| where Timestamp >= ago(lookback)
| where InitiatingProcessFileName in~ ("hfs.exe", "hfs2.exe") or InitiatingProcessVersionInfoProductName has "HTTP File Server"
| where FolderPath has_any ("\\Windows\\Temp\\", "\\ProgramData\\", "\\Users\\Public\\", "\\Startup\\", "\\Tasks\\") or FileName matches regex @"(?i)\.(exe|dll|ps1|bat|cmd|js|vbs|hta)$"
| project Timestamp, DeviceName, ActionType, FolderPath, FileName, SHA256, InitiatingProcessFileName, InitiatingProcessCommandLine
| order by Timestamp desc

Hunt 6 — Persistence established by HFS or an HFS child process

let lookback = 30d;
DeviceRegistryEvents
| where Timestamp >= ago(lookback)
| where InitiatingProcessFileName in~ ("hfs.exe", "hfs2.exe", "cmd.exe", "powershell.exe", "pwsh.exe")
| where RegistryKey has_any ("\\CurrentVersion\\Run", "\\CurrentVersion\\RunOnce", "\\Services\\", "\\Winlogon\\")
| where InitiatingProcessParentFileName in~ ("hfs.exe", "hfs2.exe") or InitiatingProcessFileName in~ ("hfs.exe", "hfs2.exe")
| project Timestamp, DeviceName, ActionType, RegistryKey, RegistryValueName, RegistryValueData, InitiatingProcessFileName, InitiatingProcessCommandLine
| order by Timestamp desc

Hunt 7 — New or rare outbound destinations from HFS

let baseline = 30d;
let recent = 2d;
let Known = DeviceNetworkEvents
| where Timestamp between (ago(baseline) .. ago(recent))
| where InitiatingProcessFileName in~ ("hfs.exe", "hfs2.exe")
| summarize by DeviceName, RemoteIP, RemoteUrl, RemotePort;
DeviceNetworkEvents
| where Timestamp >= ago(recent)
| where InitiatingProcessFileName in~ ("hfs.exe", "hfs2.exe")
| where ActionType == "ConnectionSuccess"
| join kind=leftanti Known on DeviceName, RemoteIP, RemoteUrl, RemotePort
| project Timestamp, DeviceName, InitiatingProcessCommandLine, RemoteIP, RemoteUrl, RemotePort
| order by Timestamp desc

Hunt 8 — Process-to-network correlation after HFS launches a child

let lookback = 14d;
let Children = DeviceProcessEvents
| where Timestamp >= ago(lookback)
| where InitiatingProcessFileName in~ ("hfs.exe", "hfs2.exe")
| project DeviceId, ChildTime=Timestamp, ProcessId, Child=FileName, ChildCommand=ProcessCommandLine;
DeviceNetworkEvents
| where Timestamp >= ago(lookback)
| join kind=inner Children on DeviceId, $left.InitiatingProcessId == $right.ProcessId
| where Timestamp between (ChildTime .. ChildTime + 30m)
| project Timestamp, DeviceName, ChildTime, Child, ChildCommand, RemoteIP, RemoteUrl, RemotePort, ActionType
| order by Timestamp desc

Hunt 9 — Windows Security Event process-creation fallback

let lookback = 30d;
SecurityEvent
| where TimeGenerated >= ago(lookback) and EventID == 4688
| where ParentProcessName endswith "\\hfs.exe" or ParentProcessName endswith "\\hfs2.exe"
| where NewProcessName matches regex @"(?i)\\(cmd|powershell|pwsh|wscript|cscript|mshta|rundll32|certutil)\.exe$"
| project TimeGenerated, Computer, SubjectUserName, ParentProcessName, NewProcessName, CommandLine, NewProcessId
| order by TimeGenerated desc

Detection Notes

  • Hunt 1 is the highest-value first pass. Confirm the actual executable version and listening service; renamed binaries and portable installations can evade filename matching.
  • Hunts 2 and 3 depend on HTTP request details. loginSrp1 is a published vulnerable code path, but ordinary clients also use it. A short burst from one source, followed by administrative/configuration access, is more suspicious than a single request.
  • A forged session can authenticate cleanly; failed-login analytics alone will miss it. HFS may terminate TLS itself, leaving WAF/proxy logs unavailable.
  • HFS can legitimately execute configured server-side code. Hunts 4–8 are highest signal when child processes, writable-system paths, persistence changes, or destinations are new for that host.
  • pack_all() provides schema-tolerant first-pass coverage but can be expensive. Replace it with connector-specific URI, request-body, source-IP, and action fields after confirming the deployed WAF/proxy schema.
  • Missing HTTP request logging, Defender for Endpoint process/file/registry/network telemetry, or Security Event 4688 collection prevents the corresponding layers from being visible in Sentinel.