Why the Endpoint Has No Auth
This is the part nobody's explaining.
/fortisandbox/job-detail/tracer-behavior is a polling endpoint. FortiSandbox doesn't operate in isolation, it's a node in the Fortinet Security Fabric. FortiGate, FortiMail, and FortiProxy submit samples to it via API and then poll for verdicts. The submission creates a job. The job ID comes back in the submission response. The polling client uses that job ID to check status and retrieve results.
The design assumption baked into this endpoint is: the job ID is the implicit credential. Only the system that submitted the job knows its ID, so authentication on the retrieval endpoint is redundant. The job ID is the auth token, it's just that nobody documented it as one, nobody validated its format, and nobody isolated the parameter from the shell command that processes it.
This is a pattern. Systems that treat opaque identifiers as implicit authorization tokens skip authentication on retrieval endpoints constantly. It's usually fine until someone reads the parameter directly into a shell call.
The deeper architectural reason: FortiSandbox is designed to live inside the Fortinet Security Fabric, reachable only by FortiGate, FortiMail, and FortiProxy on the internal network. The Fabric trust model is network-based: if you can reach the appliance, you are a trusted fabric member. Authentication on the polling endpoint was considered redundant because network access was the gate. This is the perimeter security model applied to an API: the perimeter was supposed to keep untrusted callers out, so the API didn't need to. The CVE exists because in some deployments the appliance is internet-reachable, and in others the "fabric" network is reachable by an attacker who has already compromised something else inside the perimeter. The assumption held until the perimeter didn't.
Why It Runs as Root
FortiSandbox's analysis engine has to run as root. It creates and destroys VMs, mounts and unmounts filesystem images, manipulates virtual network interfaces for sample isolation, injects agents into guest OSes. You cannot do that from an unprivileged process. The web server and backend that serve the UI and API endpoints run in the same privilege context, or at minimum, the subprocess they invoke to handle jid lookups does. There's no privilege separation wall between "the interface that answers HTTP requests" and "the engine that detonates malware." The endpoint gets root because the appliance needs root, and separating the two was never a design priority.
What the Backend Call Looks Like
The advisory says OS command injection via the jid parameter. The PoC uses | to inject. That specific character, not ;, not $(...), but pipe, tells you something about the backend implementation.
Semicolon injection (;cmd) works when the parameter is appended to a shell command and the entire string is evaluated. Dollar-sign injection ($(cmd)) works in the same context but with a different quoting style. Pipe injection (|cmd) works when the parameter is passed to a shell invocation where the output of the first command is being piped somewhere, the attacker's | terminates whatever the backend was piping to and starts a new command in its place.
The backend is almost certainly something like:
get_trace $jid | process_output
or equivalent Python/PHP subprocess with shell=True. The jid value breaks the pipe chain. The redirect to /web/ng/out.txt works because the web root is writable by the process, again, root.
The Endpoint That Explains What Malware Did Can Now Act Like Malware
The specific endpoint is tracer-behavior. Not a login page. Not a file upload handler. The behavioral trace endpoint, the one that returns the record of what a detonated sample did inside the VM: filesystem writes, network connections, registry modifications, process spawns. The forensic output of the sandbox.
The endpoint that tells your SOC what malware does is the endpoint that lets you do what malware does. That's not a coincidence of naming. It means the code path that retrieves behavioral trace data, already wired into the analysis engine, already running as root, is the attack surface.
What Owning the Verdict Engine Means
Coverage of this vulnerability is treating it as a generic unauth RCE on a Fortinet box. That framing undersells it.
FortiSandbox's role in the Security Fabric is to be a trust authority. FortiGate doesn't decide whether a file is malicious, FortiSandbox does, and FortiGate enforces that verdict. FortiMail doesn't detonate attachments, it forwards them to FortiSandbox and delivers or quarantines based on what comes back. The entire downstream enforcement chain is predicated on the sandbox's verdicts being correct.
When you control the sandbox, you control the verdict database. You can write verdicts. Every sample submitted after your shell is established gets evaluated by an engine you control. You can make malware look clean, the forwarded file gets delivered, the attachment opens, the download proceeds, none of the enforcement triggers fire. You can make clean files look malicious, targeted harassment, triggering false alerts that burn out analysts, poisoning threat intelligence feeds.
The credentials the appliance uses to push verdicts upstream, the API keys and certificates that authenticate FortiSandbox to FortiGate and FortiMail, are stored on the box. Root access is access to those credentials. You're not just inside the sandbox. You're holding the badge that every downstream system trusts unconditionally.
The analyst's ticket backlog is also in scope. FortiSandbox maintains a database of verdicts for samples already submitted. An attacker with root access can write to that database directly. Every sample sitting in the pending-review queue, everything flagged in the last week and still under investigation, becomes a candidate for verdict modification. The analyst closes tickets. The items they close are the ones the attacker cleared.
The Five Months
Discovered November 2025. Patched and disclosed April 2026.
Responsible disclosure windows exist to give vendors time to patch before the public knows what to exploit. They also define, precisely, the window during which defenders cannot patch because the patch doesn't exist. Every organization running FortiSandbox 4.4.x was running a vulnerable system from November through April. They couldn't know. They couldn't act. The disclosure window is by design a period of mandated exposure.
The question for five months of a pre-auth root shell on an appliance with this much access isn't whether the vulnerability was known, it was, to the researcher and to Fortinet. The question is whether it was independently discovered by someone who didn't report it. There's no mechanism to answer that question after the fact.
Two PoC repos from researchers who aren't Samuel de Lucas Maroto appeared within days of public disclosure:
The gap between "two PoC repos" and "operational tooling in criminal infrastructure" is measured in days, not weeks. That's the window you're now in.