Skip to content

Hunt Ivanti CVE-2026-104935 in Your Proxy Logs Before the Board Asks

Hunt Ivanti CVE-2026-104935: X-DSCGI-PATH Mismatches in Proxy Logs

Hunt Ivanti CVE-2026-104935 in Your Proxy Logs Before the Board Asks

Volexity handed defenders a beautiful tell: the URL says welcome.cgi, the header says wu.cgi or a /tmp MD5 path. If your reverse proxy logs custom headers, you can hunt this with grep before someone schedules a “synergy sync” about it.

Lab only. Everything below runs against a synthetic nginx access.log on this machine. The attacker IP and header patterns are taken from Volexity’s public writeup of UTA0576 / CVE-2026-104935, planted into fake logs for teaching. Do not point these commands at systems you do not own or lack authorization to examine. Hunting production logs you are paid to defend is fine. Scanning someone else’s VPN is not a lab.

CVE-2026-104935 is the Ivanti Connect Secure auth-bypass + RCE pair that hit CISA KEV on October 13, 2026. Full incident context is in our breaking piece. This post is the hands-on: build a tiny lab log, find the mismatch, confirm the MD5 race paths, and leave with copy-paste detections for your real SIEM.

What you need logged

On whatever sits in front of ICS (nginx, httpd, a WAF, a load balancer), log the request URI and the X-DSCGI-PATH header. In nginx that is roughly:

log_format ivanti '$remote_addr - $remote_user [$time_local] '
                  '"$request" $status $body_bytes_sent '
                  '"$http_referer" "$http_user_agent" '
                  '"X-DSCGI-PATH: $http_x_dscgi_path"';
access_log /var/log/nginx/ivanti_access.log ivanti;

If you do not log that header today, you are flying blind on this specific chain. Fix the logging, then hunt. Order matters.

Lab setup

We generated a 53-line synthetic access.log with normal welcome.cgi traffic mixed with five UTA0576-shaped POSTs from 108.165.147.64 (the Evoxt VPS IP Volexity published). Headers point at wu.cgi and at /home/runtime/tmp/<md5> paths. No real appliance was touched.

Kali terminal: wc and grep counting welcome.cgi hits, then top talkers showing 108.165.147.64 with 13 hits versus a handful of internal and benign IPs.
Step 1: volume check. One external IP owns most of the welcome.cgi traffic.

Step 1: who loves welcome.cgi

The auth bypass rides the public login path. Count it, then rank talkers:

grep -c "welcome.cgi" access.log
grep "welcome.cgi" access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head

In the lab, 24 lines hit welcome.cgi. Thirteen of them are the planted attacker IP. Bursts from one host beat a slow drip from your users.

Step 2: the tell (header mismatch)

Kali terminal: grep for X-DSCGI-PATH showing five POST lines to welcome.cgi with headers pointing at wu.cgi and /home/runtime/tmp MD5 paths, then a uniq count of those header targets.
Step 2: every malicious line keeps the welcome.cgi URL and swaps the real target into X-DSCGI-PATH.
grep "X-DSCGI-PATH" access.log
grep -oE 'X-DSCGI-PATH: [^"]+' access.log | sort | uniq -c

Healthy traffic should not send X-DSCGI-PATH at all, or should never point it at wu.cgi / /home/runtime/tmp/ while the URL stays on welcome.cgi. Volexity’s guidance is blunt: monitor mismatches between the URL path and that header.

Step 3: confirm the MD5 race pattern

Kali terminal: Python printing MD5 hashes for drop.zip, x.pl.zip, and gate.zip, then showing the first and last X-DSCGI-PATH timestamps and a count of 13 log lines from the attacker IP.
Step 3: temp paths are MD5(filename). Match them to uploads if you have the bodies. Timeline and IOC count close the loop.
python3 - <<'PY'
import hashlib
for name in ["drop.zip", "x.pl.zip", "gate.zip"]:
    print(name, "=>", hashlib.md5(name.encode()).hexdigest())
PY

grep "X-DSCGI-PATH" access.log | awk -F'[][]' '{print $2}' | head -1
grep "X-DSCGI-PATH" access.log | awk -F'[][]' '{print $2}' | tail -1
grep "108.165.147.64" access.log | wc -l

Lab output: drop.zip hashes to 64f2136d11501c80de665dcdb55be3f5, which appears verbatim in the planted header. First malicious header at 05/Oct/2026:10:00:00, last eight minutes later. Thirteen total lines from that IP including recon GETs. That is enough to page someone.

Drop these in the SIEM

  • Any request where URI contains welcome.cgi AND X-DSCGI-PATH contains wu.cgi or /home/runtime/tmp/
  • Rate spike: more than N welcome.cgi requests per 5 minutes from one source
  • Known bad: 108.165.147.64 (rotate as intel updates; one IP is not a career)
  • On the appliance (if you have shell): unexpected files under /tmp/, sniffer binaries under hidden dirs like .icscap, gaps in debuglog / audit.log
Patch still comes first. Hunting is how you find the bodies the Integrity Checker missed. It is not a substitute for upgrading to 22.8R2.5 / 25.1.1.2 / 25.1.3.x. A beautiful detection rule on an unpatched edge box is a museum piece.

Sloth take

Defenders keep asking for “advanced threat hunting” while leaving the one header that matters out of the access log. Log X-DSCGI-PATH. Grep for mismatches. Patch the appliance. Then you can go back to arguing about whether the SOC needs another dashboard.

Need a grown-up to look at your edge stack? Book a slot with Dark Edge Consulting. We do the boring, careful work so you can go back to ignoring your inbox.

Sources