FlawOpen

flawopen.com/Teardowns/cve-2026-105752-vllm-harmony-cache-salt-omission

● CVE-2026-105752 · CVSS 3.1 · Basse
Recherche · FlawOpen

CVE-2026-105752 : omission de cache_salt dans vLLM

Une continuation d’outil GPT-OSS dans Responses de vLLM pouvait omettre cache_salt et utiliser un espace de cache de préfixes sans salt. Passez à vLLM 0.30.0 ou ultérieur et conservez les salts par locataire dans chaque continuation.[1], [5]

💡 Explication en Langage Simple (ELI5)

Imaginez les documents de chaque client rangés dans des casiers portant une étiquette de couleur privée. La première requête a la bonne étiquette, mais un outil la perd en rendant les documents pour l’étape suivante. Une étagère partagée peut indiquer par un succès de cache si des pages supposées s’y trouvent déjà ; elle ne remet pas les pages.[1]

Concepts Clés et Termes

Prefix caching
Réutilise les blocs clé/valeur du modèle pour des préfixes identiques.[6]
cache_salt
Valeur intégrée au hachage du premier bloc pour séparer les caches aux salts différents.[6]
Harmony continuation
Entrée suivante du modèle après une réponse Harmony, y compris après un outil.[1]
Membership oracle
Signal de présence d’un préfixe supposé sans révéler son contenu.[1]
CWE-524
Utilisation d’un cache contenant des informations sensibles ; classification principale de l’avis.[1]

Correspondances de référentiels

  • Référence CWE pour la faiblesse décrite dans ce guide : CWE-524

Analyse de Cause Racine

L’avis vLLM décrit GPT-OSS Harmony sur POST /v1/responses. L’entrée initiale transmettait request.cache_salt à tokens_input ; après un outil intégré ou MCP, la continuation utilisait tokens_input(token_ids) sans salt. Le helper ne stocke le salt que s’il est fourni. Avec le cache automatique des préfixes dans un déploiement partagé, la continuation utilisait donc l’espace sans salt. L’avis cite les versions antérieures à 0.30.0, confirme le comportement en 0.25.1 et précise que la borne basse n’est pas établie. Le résultat est un signal d’appartenance au cache via cached_tokens_per_turn, pas la divulgation directe d’un texte de prompt arbitraire. CWE-200 est aussi cité comme impact ; CWE-524 est l’unique faiblesse principale ici.[1], [3], [4]

Déroulement de l'Attaque Étape par Étape

Étape 1

Un service partagé réunit les prérequis

Il faut une version concernée, GPT-OSS Harmony Responses, le cache de préfixes et un outil ; la victime définit cache_salt et atteint la continuation.[1]

Étape 2

La première entrée du moteur reçoit le salt

L’appel initial de tokens_input inclut request.cache_salt et place le premier préfixe dans l’espace salé de l’appelant.[1]

Étape 3

La continuation de l’outil perd le salt

Après le résultat de l’outil, la continuation appelle tokens_input(token_ids) sans le salt initial ; le préfixe peut rejoindre l’espace partagé non salé.[1]

Étape 4

Un compteur de cache peut révéler une appartenance

Un locataire qui reconstitue le préfixe après l’outil peut consulter cached_tokens_per_turn pour déduire son appartenance, pas récupérer un prompt arbitraire.[1]

Étape 5

Le renderer conserve le salt à chaque tour

La refactorisation fusionnée conserve cache_salt pendant le rendu Harmony et le transmet à chaque nouvelle entrée moteur ; passez à 0.30.0+.[1], [3], [7]

Code Source : Vulnérable vs Sécurisé

L’avis vLLM décrit GPT-OSS Harmony sur POST /v1/responses. L’entrée initiale transmettait request.cache_salt à tokens_input ; après un outil intégré ou MCP, la continuation utilisait tokens_input(token_ids) sans salt. Le helper ne stocke le salt que s’il est fourni. Avec le cache automatique des préfixes dans un déploiement partagé, la continuation utilisait donc l’espace sans salt. L’avis cite les versions antérieures à 0.30.0, confirme le comportement en 0.25.1 et précise que la borne basse n’est pas établie. Le résultat est un signal d’appartenance au cache via cached_tokens_per_turn, pas la divulgation directe d’un texte de prompt arbitraire. CWE-200 est aussi cité comme impact ; CWE-524 est l’unique faiblesse principale ici. Upstream excerpts, not a literal line-by-line diff.[1], [3], [4], [7]

Extrait source: renderer Harmony Responses de vLLM (extraits de versions distinctes)

IMPLÉMENTATION VULNÉRABLE
# Le chemin de la requête initiale utilisait le salt, contrairement à la continuation après l’outil.
engine_input = tokens_input(token_ids, cache_salt=request.cache_salt)

# Après le résultat d’un outil, la continuation reconstruisait l’entrée ainsi :
engine_input = tokens_input(token_ids)
PATCH SÉCURISÉ ET ROBUSTE
# Conserver le salt de la requête dans le contexte de rendu Harmony.
cache_salt = cast(str | None, engine_input.get("cache_salt"))
engine_input = self.online_renderer.render_responses_harmony_messages(
    context.messages,
    cache_salt=cache_salt,
    tok_params=tok_params,
)

# Le moteur de rendu fournit le salt chaque fois qu’il crée l’entrée du moteur.
engine_input = tokens_input(prompt["prompt_token_ids"], cache_salt=cache_salt)

Liste de Contrôle de Sécurité pour l'Ingénierie

Sources