CVE-2026-111057 Splunk · SPL

Detect Mercury Unauthenticated RCE via /api/terminals Access Control Bypass (CVE-2026-111057) in Splunk

Detects exploitation of CVE-2026-111057, a CVSS 10.0 unauthenticated remote code execution vulnerability in mljar Mercury (pip package) versions >= 3.0.0 and <= 3.2.3. A flawed regular expression used for access control (CWE-185) allows attackers to bypass authentication (CWE-284) on the /api/terminals endpoint, which exposes an interactive terminal/WebSocket interface. Unauthenticated attackers can open a terminal session and execute arbitrary OS commands in the context of the Mercury server process. This detection looks for anomalous HTTP/WebSocket access to /api/terminals endpoints, terminal session establishment without preceding authentication, and child-process command execution spawned from the Mercury/python/gunicorn/uvicorn process tree. Fixed in v3.2.4 (commit 8c467129037ee9df269d543ac217ffd33b97bf3f).

MITRE ATT&CK

Tactic
Initial Access Execution

SPL Detection Query

Splunk (SPL)
spl
index=web (uri_path="*/api/terminals*" OR uri_path="*/terminals/*")
| eval ws_upgrade=if(status=101,"yes","no")
| eval no_auth=if(isnull(user) OR user="-" OR user="","yes","no")
| where no_auth="yes" AND (status=101 OR status=200 OR status=201 OR status=204)
| stats count AS req_count values(http_method) AS methods values(status) AS statuses values(http_user_agent) AS user_agents dc(uri_path) AS distinct_paths by src_ip dest host
| where req_count>=1
| sort - req_count
critical severity medium confidence

Finds unauthenticated requests to the Mercury /api/terminals endpoint in web/proxy access logs, flagging WebSocket upgrade (101) responses that indicate an established terminal session. Correlate with endpoint process telemetry for confirmation of RCE.

Data Sources

Web Server Access LogsReverse Proxy Logs

Required Sourcetypes

access_combinednginx:plus:accessms:iis:auto

False Positives & Tuning

  • Authenticated admin terminal usage where the proxy does not forward a username to the access log.
  • Authorized penetration testing or scanning traffic against the terminal endpoint.
  • Automated monitoring probes hitting the endpoint without credentials.

Other platforms for CVE-2026-111057


Testing Methodology

Validate this detection against 3 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.

  1. Test 1 Unauthenticated access to Mercury /api/terminals endpoint

    Expected signal: Web/proxy access log entry for GET /api/terminals with no authenticated username and a 2xx/101 response code.

  2. Test 2 Establish WebSocket terminal session via bypass

    Expected signal: HTTP 101 Switching Protocols response logged for /api/terminals from an unauthenticated client; WebSocket connection record.

  3. Test 3 Command execution from Mercury process tree

    Expected signal: Process-start events showing /bin/sh, id, whoami, and curl spawned with a python parent process.


Response Playbook

Triage

  1. Confirm the affected host is running mljar Mercury via pip and determine the installed version (e.g., `pip show mercury`); versions >= 3.0.0 and <= 3.2.3 are vulnerable, 3.2.4+ is patched.
  2. Review web/proxy logs for the source IP(s) that accessed /api/terminals and determine whether any request lacked authentication and received a 101 (WebSocket upgrade) or 2xx response indicating a successful terminal session.
  3. Correlate the terminal access timestamps with endpoint process-execution telemetry to identify any shell or command processes spawned from the Mercury/python/gunicorn/uvicorn parent process.
  4. Determine whether the source IP is internal, external, or a known scanner, and whether the access pattern is interactive (sustained WebSocket) versus a one-off probe.

Containment

  1. Immediately block the offending source IP(s) at the perimeter/WAF and restrict access to the Mercury /api/terminals endpoint.
  2. Upgrade Mercury to v3.2.4 or later, or take the Mercury service offline until patched; as an interim control, place the app behind an authenticating reverse proxy that denies unauthenticated access to /api/terminals.
  3. If command execution is confirmed, isolate the affected host from the network to prevent lateral movement.

Evidence Collection

  1. Preserve web server, reverse proxy, and WebSocket access logs covering the suspected exploitation window, including full request URIs, status codes, and source IPs.
  2. Capture process-execution logs (EDR/auditd/sysmon-for-linux) showing child processes spawned by the Mercury server process, including command lines and process trees.
  3. Snapshot the host filesystem and memory if RCE is confirmed, and collect any dropped files, cron entries, or new user accounts created during the window.

Escalation Criteria

  • !Escalate to incident response immediately if process-execution telemetry confirms shell or command execution originating from the Mercury process tree following unauthenticated terminal access.
  • !Escalate if evidence of persistence (new accounts, cron jobs, modified startup scripts), credential access, or lateral movement is found on the affected host.
  • !Escalate if the Mercury instance is internet-facing and unpatched, given the CVSS 10.0 unauthenticated RCE exposure.

Investigation Guide

Related Techniques

Forensic Artifacts

  • >Web/proxy access log entries showing /api/terminals requests with HTTP 101 upgrades or 2xx responses from unauthenticated clients.
  • >Child processes (sh, bash, curl, wget, nc, python) parented by the Mercury/gunicorn/uvicorn process, visible in EDR/auditd telemetry.
  • >WebSocket connection records and any temporary files, reverse-shell binaries, or scripts dropped during the session.

Tuning Guidance

Baseline which source IPs and users legitimately access /api/terminals in your environment; if the Mercury terminal feature is used by administrators, allowlist their IPs and focus alerting on unauthenticated (empty username) access and WebSocket upgrades from unexpected sources. Where a reverse proxy strips usernames, rely on the process-execution correlation (shell children of the Mercury process) rather than log-only auth state. Suppress known vulnerability scanners by source IP. After upgrading to Mercury 3.2.4+, shift the detection to a pure anomaly/monitoring posture since the bypass is patched.


Hunting Queries

Surfaces all WebSocket upgrade (101) events against the Mercury terminal endpoint grouped by source IP and user to find unauthenticated interactive terminal sessions.

Hunting — KQL
kql
W3CIISLog | where csUriStem has "/api/terminals" | where scStatus == 101 | summarize count() by cIP, csUsername, bin(TimeGenerated, 1h) | order by count_ desc
Hunting — SPL
spl
index=web uri_path="*/api/terminals*" status=101 | stats count by src_ip user | sort - count

Hunts for shell and reconnaissance child processes spawned from the Mercury server process tree, indicating command execution via the terminal bypass.

Hunting — KQL
kql
DeviceProcessEvents | where InitiatingProcessFileName in~ ("python", "python3", "gunicorn", "uvicorn", "mercury") | where FileName in~ ("sh", "bash", "dash", "curl", "wget", "nc", "ncat", "whoami", "id") | project TimeGenerated, DeviceName, InitiatingProcessFileName, FileName, ProcessCommandLine
Hunting — SPL
spl
index=edr parent_process_name IN ("python","python3","gunicorn","uvicorn","mercury") process_name IN ("sh","bash","curl","wget","nc","whoami","id") | table _time host parent_process_name process_name process

Atomic Red Team Tests

Test 1 Unauthenticated access to Mercury /api/terminals endpoint
linux

Simulates an unauthenticated HTTP request to the vulnerable /api/terminals endpoint to verify web-log detection fires. Lab-only against a test Mercury instance.

Command

bash
curl -s -o /dev/null -w "%{http_code}" -X GET "http://127.0.0.1:8000/api/terminals" -H "User-Agent: cve-2026-111057-test"

Cleanup

bash
rm -f /tmp/mercury_test_response.txt 2>/dev/null || true

Expected Telemetry

Web/proxy access log entry for GET /api/terminals with no authenticated username and a 2xx/101 response code.

Expected Detection

The kql/spl/qradar_aql/sumo_logic/chronicle_yaral queries flag the unauthenticated request to /api/terminals.

Test 2 Establish WebSocket terminal session via bypass
linux

Simulates establishing a WebSocket terminal session to /api/terminals without authentication using a scripted client. Lab-only.

Command

bash
python3 -c "import socket; s=socket.create_connection(('127.0.0.1',8000)); s.sendall(b'GET /api/terminals HTTP/1.1\r\nHost: 127.0.0.1\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n\r\n'); print(s.recv(256)); s.close()"

Cleanup

bash
echo 'no cleanup required'

Expected Telemetry

HTTP 101 Switching Protocols response logged for /api/terminals from an unauthenticated client; WebSocket connection record.

Expected Detection

The kql and spl WebSocket-upgrade (status 101) queries and the chronicle_yaral rule detect the upgrade on the terminal endpoint.

Test 3 Command execution from Mercury process tree
linux

Simulates post-exploitation command execution by spawning a shell/recon command as a child of a python process standing in for the Mercury server. Lab-only.

Command

bash
python3 -c "import subprocess; subprocess.run(['/bin/sh','-c','id; whoami; curl -s http://127.0.0.1/ >/dev/null'])"

Cleanup

bash
echo 'no cleanup required'

Expected Telemetry

Process-start events showing /bin/sh, id, whoami, and curl spawned with a python parent process.

Expected Detection

The elastic_eql sequence and crowdstrike_cql query detect shell/recon child processes parented by the Mercury/python process tree.

Related Detections