flawopen.com/Teardowns/cve-2026-71433-langgraph-store-namespace-boundary
LangGraph CVE-2026-71433: fuga de namespaces
Las lecturas con ámbito en Postgres y SQLite de LangGraph podían cruzar límites de namespace y exponer datos de tenants vecinos. Actualiza ambos paquetes a 3.1.1.
Vector CVSS
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:NImagina que pides al bibliotecario una carpeta cuyo nombre empieza por «equipo». Si el catálogo busca solo el texto inicial, podría devolver «equipo2» junto con «equipo». LangGraph unía las etiquetas del namespace con puntos y usaba un patrón de prefijo que no exigía ese punto como límite. La corrección exige el namespace exacto o un segmento siguiente real, para que la carpeta de un tenant no se confunda con la de otro.
Conceptos Clave y Términos
Namespace- Una tupla de etiquetas que LangGraph Store usa para agrupar elementos. Una aplicación puede usarla como límite entre usuarios o tenants.
Ámbito por prefijo- Una solicitud para leer un namespace y sus descendientes. La coincidencia correcta respeta el límite del segmento:
fooincluyefoo.child, pero no el namespace hermanofoobar. Patrón SQL `LIKE`- Un patrón de texto donde
%coincide con cualquier secuencia y_con un carácter. Hay que escapar estos caracteres si las etiquetas del namespace deben tratarse literalmente. CWE-863- Autorización incorrecta: el Store devolvió registros fuera del namespace que el llamante tenía permiso para leer.
Mapeos de marcos
- Referencia CWE para la debilidad descrita en esta guía: CWE-863
Análisis de Causa Raíz
Antes de 3.1.1, los Stores de checkpoint para Postgres y SQLite aplanaban las tuplas de namespace con puntos y limitaban las búsquedas con LIKE '<namespace>%'. LIKE no entiende el separador del namespace, así que una consulta para foo también podía coincidir con el namespace hermano foobar; las etiquetas válidas % y _ podían actuar como comodines. list_namespaces tenía errores relacionados de prefijo y sufijo. Bastaba una lectura normal con ámbito: no se necesitaba una entrada malformada. El problema se limita a las rutas de lectura search y listado de namespaces de los Stores Postgres/SQLite cuando la aplicación depende del namespace para separar tenants. get, put y delete usan igualdad exacta y no estaban afectados; InMemoryStore compara los elementos del namespace y tampoco estaba afectado. La corrección exige igualdad exacta o un punto antes de los descendientes, escapa metacaracteres de LIKE y usa patrones por segmento al listar namespaces. En SQLite también evita el comportamiento de LIKE que ignora diferencias ASCII entre mayúsculas y minúsculas. El aviso no informa de explotación conocida. Los paquetes afectados se corrigieron en 3.1.1.
Matriz de exposición de CVE-2026-71433 por despliegue
| Despliegue y forma del namespace | Comportamiento documentado | Acción de triaje |
|---|---|---|
| PostgresStore / AsyncPostgresStore o SqliteStore / AsyncSqliteStore anterior a 3.1.1; el aislamiento entre tenants depende de namespaces. | Una búsqueda search o list_namespaces con ámbito puede alcanzar un namespace hermano si las etiquetas comparten un prefijo textual (foo / foobar, 1 / 12) o contienen % / _. En SQLite, la búsqueda también igualaba diferencias solo de mayúsculas ASCII. | Actualiza el paquete checkpoint correspondiente a 3.1.1 o posterior. Prueba prefijos hermanos, caracteres comodín, coincidencias de sufijo y diferencias de mayúsculas/minúsculas en el backend de producción. |
| Store SQLite anterior a 3.1.1 con etiquetas de namespace que solo difieren en mayúsculas ASCII. | La búsqueda vulnerable de descendientes usaba LIKE sin distinguir mayúsculas, mientras que las operaciones exactas sí las distinguían. | Actualiza y añade una prueba de regresión de mayúsculas si las etiquetas pueden diferir así. |
Etiquetas UUID de longitud fija sin % ni _. | El aviso indica que este esquema no está afectado: las etiquetas de longitud fija no pueden ser prefijos entre sí. | Confirma que todos los segmentos cumplen esa invariante. Si las etiquetas pueden variar o contener comodines, considera el despliegue afectado. |
| InMemoryStore. | No está afectado: compara individualmente los elementos del namespace. | No hace falta actualizar por este CVE; conserva las comprobaciones de propiedad del tenant en el límite de la aplicación. |
| Despliegue hospedado de LangSmith. | El valor predeterminado LANGGRAPH_STORE_BACKEND=python usa AsyncPostgresStore y entra en el alcance con un paquete afectado. El backend independiente grpc recibió una corrección equivalente. | Comprueba el backend configurado y la versión desplegada; confirma la versión o la actualización hospedada en vez de deducir la exposición por el nombre del producto. |
Flujo de Ataque Paso a Paso
Comprueba el backend y las etiquetas
La instalación debe usar langgraph-checkpoint-postgres o langgraph-checkpoint-sqlite anterior a 3.1.1 y depender del namespace para separar usuarios o tenants. Los prefijos coincidentes o las etiquetas % y _ hacen relevante este límite.
Se realiza una lectura normal con ámbito
Una solicitud autenticada de la aplicación busca un namespace como foo. No hace falta enviar un payload especial: el namespace normal es la entrada del comparador defectuoso.
El backend aplana y compara patrones
El Store une las etiquetas con puntos y usa un prefijo LIKE terminado en %. Como no exige el separador, foo puede coincidir con foobar; los caracteres de patrón en las etiquetas también pueden ampliar la coincidencia.
Pueden devolverse elementos de un namespace vecino
Si la aplicación trata los namespaces como límites entre tenants, la búsqueda o el listado puede devolver elementos guardados de otro usuario. Es un problema de confidencialidad de lectura, no SQL injection ni acceso de escritura.
Actualiza y vuelve a probar el aislamiento
Actualiza ambos paquetes aplicables a 3.1.1 o posterior. Prueba prefijos de namespaces vecinos, etiquetas literales % y _, coincidencias de sufijo y el comportamiento de mayúsculas/minúsculas de SQLite con tenants de prueba separados.
Código Fuente: Vulnerable vs. Seguro
El predicado vulnerable considera descendiente cualquier cadena que comienza con el namespace aplanado. La corrección añade una comparación exacta y exige un punto literal antes de los segmentos descendientes; también escapa la barra invertida, % y _ en el patrón LIKE. El commit upstream también sustituye los patrones de prefijo/sufijo de list_namespaces por coincidencias conscientes de segmentos y ajusta la búsqueda SQLite. Es un fragmento de código, no un módulo completo.
Fragmento de origen: libs/checkpoint-postgres/langgraph/store/postgres/base.py
def _prepare_batch_search_queries(op):
ns_condition = "TRUE"
ns_param = None
if op.namespace_prefix:
ns_condition = "store.prefix LIKE %s"
ns_param = (f"{_namespace_to_text(op.namespace_prefix)}%",)
return ns_condition, ns_param
def _escape_like_literal(text: str) -> str:
return text.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_")
def _namespace_prefix_condition(namespace_prefix: tuple[str, ...]) -> tuple[str, tuple]:
path = _namespace_to_text(namespace_prefix)
condition = r"(store.prefix = %s OR store.prefix LIKE %s ESCAPE '\\')"
return condition, (path, f"{_escape_like_literal(path)}.%")
if op.namespace_prefix:
ns_condition, ns_param = _namespace_prefix_condition(op.namespace_prefix)
Lista de Verificación de Seguridad para Ingeniería
- ✓Actualiza
langgraph-checkpoint-postgresylanggraph-checkpoint-sqlitea 3.1.1 o posterior en todas las instalaciones. - ✓Añade regresiones en las que la etiqueta de un tenant sea prefijo de otra, como
fooyfoobar, y comprueba que cada búsqueda solo devuelve el namespace solicitado y sus descendientes. - ✓Prueba etiquetas con
%,_, barras invertidas y diferencias solo de mayúsculas/minúsculas usando exactamente el backend de base de datos de producción. - ✓Prueba
list_namespacescon prefijo, sufijo, comodín y ruta vacía; exige que*coincida con exactamente un segmento, según la documentación. - ✓Mantén las comprobaciones de autorización en el límite de la aplicación; los IDs de namespace opacos o de formato fijo no sustituyen la verificación de propiedad del tenant.