FlawOpen

flawopen.com/AI Security/langgraph-js-custom-auth-cross-user-store-access

● CWE-639 / CWE-863 · CVSS v4 8.6[1] · Haute
Recherche · FlawOpen

LangGraph JS Auth : accès inter-utilisateurs au Store

langgraph-api <0.15.0 pouvait perdre les namespaces Store réécrits par custom-auth JS/TS, ouvrant un accès inter-utilisateurs. Passez à 0.15.0.[1], [2]

Vecteur CVSSCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N[1]
💡 Explication en Langage Simple (ELI5)

Imaginez un bibliothécaire qui vérifie votre carte puis demande à un autre comptoir de récupérer un livre. Le second comptoir inscrit votre étagère, mais le changement se perd lors du transfert et il récupère celle indiquée initialement par le visiteur. Le chemin d’authentification JavaScript/TypeScript concerné pouvait perdre la réécriture du namespace entre le runtime d’autorisation et l’opération Store. Le correctif transmet le namespace autorisé et le valide avant d’utiliser le Store.[1]

Concepts Clés et Termes

GHSA-4hm6-w6qq-w73v
Avis LangGraph de gravité élevée publié le 28 septembre 2026. Aucun CVE n’est attribué. Le paquet concerné est langgraph-api, corrigé en version 0.15.0.[1]
Namespace Store
Nom hiérarchique qui regroupe les enregistrements LangGraph Store. Les applications y incluent souvent l’identité de l’utilisateur ou du tenant pour séparer les données.[1]
Handler d’autorisation personnalisé
Code applicatif qui décide si une requête authentifiée peut accéder à une ressource et peut réécrire le namespace avant l’opération Store.[1]
CWE-639 / CWE-863
Contournement d’autorisation via une clé contrôlée par l’utilisateur et autorisation incorrecte. Le défaut consiste à ne pas appliquer la restriction de namespace du handler.[1], [3], [4]

Correspondances de référentiels

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

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

Étape 1

Vérifier si le déploiement est concerné

Vérifiez que langgraph-api est en version >=0.1.2 et <0.15.0 et que le serveur utilise un handler personnalisé JavaScript ou TypeScript.[1]

Étape 2

Repérer la réécriture du namespace

Le handler modifie le namespace demandé pour inclure ou imposer l’identité de l’utilisateur authentifié au lieu de rejeter une requête hors de ce namespace.[1]

Étape 3

Le résultat d’autorisation franchit une frontière de runtime

Dans les versions concernées, la modification du namespace peut ne pas être transmise à l’opération Store. Le namespace initial fourni par le demandeur peut rester utilisé.[1]

Étape 4

Un utilisateur authentifié vise un autre namespace

Un compte ordinaire peut demander des opérations Store sur des enregistrements hors de son namespace. L’avis cite la lecture, l’écrasement, la recherche et la suppression.[1]

Étape 5

Mettre à niveau ou refuser les namespaces non autorisés

Passez à langgraph-api>=0.15.0. Si ce n’est pas immédiat, rejetez les namespaces non autorisés pour chaque action Store et vérifiez le namespace effectivement reçu par le Store.[1], [2]

Analyse de Cause Racine

Le GHSA des mainteneurs LangGraph, publié le 28 septembre 2026, décrit un défaut dans langgraph-api versions >=0.1.2 et <0.15.0 lorsque toutes ces conditions sont réunies : le déploiement utilise une authentification personnalisée JavaScript ou TypeScript ; le handler d’autorisation Store réécrit le namespace demandé pour limiter les données à l’utilisateur courant ; un utilisateur authentifié ordinaire peut envoyer des opérations Store ; et les données de plusieurs utilisateurs passent par ce chemin. L’avis précise que les handlers Python ne sont pas concernés et que les handlers JavaScript/TypeScript qui rejettent les namespaces non autorisés au lieu de les réécrire ne le sont pas non plus. La modification du namespace par le handler pouvait être perdue à la frontière entre runtimes ; l’opération Store utilisait alors le namespace initial de la requête. Un utilisateur authentifié pouvait lire, écraser, rechercher ou supprimer des enregistrements hors de son namespace autorisé. Le problème ne contourne pas la connexion et ne permet pas une attaque distante non authentifiée. L’avis le classe Élevé, CVSS 4.0 8,6, et attribue CWE-639 et CWE-863. La version 0.15.0 transmet les changements du handler, valide le namespace final et rejette les modifications incorrectes ou non appliquées. Si la mise à niveau est différée, le contournement recommandé consiste à rejeter les namespaces non autorisés pour chaque action Store. Le code est une illustration TypeScript réduite du flux de données, pas le code source du SDK.[1]

Code Source : Vulnérable vs Sécurisé

Cet exemple TypeScript réduit illustre un contrat de frontière ; les noms des fonctions et la forme du résultat sont illustratifs, et ne proviennent pas du SDK LangGraph. L’avis établit que des changements d’autorisation JS/TS pouvaient être perdus avant l’opération Store, mais ne publie pas cette implémentation interne exacte. La partie vulnérable représente donc uniquement l’invariant documenté : le Store utilise le namespace de la requête au lieu du namespace autorisé. La partie corrigée consomme et valide le résultat autorisé. Le contournement documenté par le mainteneur consiste à rejeter les namespaces non autorisés, plutôt qu’à les réécrire, pour chaque action Store.[1]

Extrait source: Frontière d’autorisation entre LangGraph API et Store — contrat illustratif réduit

IMPLÉMENTATION VULNÉRABLE
type StoreRequest = { namespace: string[]; key: string };
type AuthorizationResult = { allowed: boolean; namespace: string[] };

async function readStore(userId: string, request: StoreRequest) {
  const authorization = await authorizeStore(userId, request); // Illustrative bridge contract.
  return store.get(request.namespace, request.key); // The bridge drops the authorized result.
}
PATCH SÉCURISÉ ET ROBUSTE
type StoreRequest = { namespace: string[]; key: string };
type AuthorizationResult = { allowed: boolean; namespace: string[] };

async function readStore(userId: string, request: StoreRequest) {
  const authorization = await authorizeStore(userId, request); // Illustrative bridge contract.
  if (!authorization.allowed) throw new Error("forbidden");
  const namespace = validateAuthorizedNamespace(userId, authorization.namespace);
  return store.get(namespace, request.key); // Apply the authorized result.
}

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

Sources

← AI Security Directory →