FlawOpen

flawopen.com/Teardowns/cve-2026-71433-langgraph-store-namespace-boundary

● CVE-2026-71433 · CVSS 5.3 · Média
Pesquisa · FlawOpen

LangGraph CVE-2026-71433: vazamento de namespace

Consultas com escopo no Postgres e SQLite do LangGraph podiam atravessar limites de namespace e expor dados de outro tenant. Atualize os dois pacotes para 3.1.1.

Vetor CVSSCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N
💡 Explicação em Linguagem Simples (ELI5)

Imagine pedir ao bibliotecário uma pasta cujo nome começa com “equipe”. Se o catálogo buscar apenas o texto inicial, ele pode devolver “equipe2” junto com “equipe”. O LangGraph juntava os rótulos do namespace com pontos e usava um padrão de prefixo sem exigir esse ponto como limite. A correção exige o namespace exato ou um segmento seguinte de verdade, evitando que a pasta de um tenant seja confundida com a de outro.

Conceitos Centrais e Termos

Namespace
Uma tupla de rótulos usada pelo Store do LangGraph para agrupar itens. Uma aplicação pode usá-la como limite entre usuários ou tenants.
Escopo por prefixo
Uma solicitação para ler um namespace e seus descendentes. A correspondência correta respeita o limite do segmento: foo inclui foo.child, mas não o namespace irmão foobar.
Padrão SQL `LIKE`
Um padrão textual no qual % corresponde a qualquer sequência e _ a um caractere. Esses caracteres devem ser escapados quando os rótulos do namespace são literais.
CWE-863
Autorização incorreta: o Store retornou registros fora do namespace que o chamador podia ler.

Mapeamentos de frameworks

  • Referência CWE para a fraqueza descrita neste guia: CWE-863

Análise de Causa Raiz

Antes da versão 3.1.1, os Stores de checkpoint Postgres e SQLite achatavam tuplas de namespace usando pontos e limitavam a busca com LIKE '<namespace>%'. O LIKE não entende o separador do namespace; por isso, uma consulta por foo também podia corresponder ao namespace irmão foobar. Os rótulos legais % e _ também podiam atuar como curingas. list_namespaces tinha erros relacionados de prefixo e sufixo. Uma leitura normal com escopo já bastava; não era necessário enviar entrada malformada. O problema afeta somente os caminhos de leitura search e listagem de namespaces nos Stores Postgres/SQLite quando a aplicação depende do namespace para separar tenants. get, put e delete usam igualdade exata e não foram afetados; InMemoryStore compara os elementos do namespace e também não foi afetado. A correção exige igualdade exata ou um ponto antes dos descendentes, escapa metacaracteres do LIKE e usa padrões por segmento na listagem. No SQLite, a busca também evita o comportamento do LIKE que ignora diferenças de maiúsculas/minúsculas ASCII. O comunicado não relata exploração conhecida. Os pacotes afetados foram corrigidos na versão 3.1.1.

Matriz de exposição do CVE-2026-71433 por implantação

Implantação e formato do namespaceComportamento documentadoAção de triagem
PostgresStore / AsyncPostgresStore ou SqliteStore / AsyncSqliteStore anterior à 3.1.1; o isolamento entre tenants depende de namespaces.Uma busca search ou list_namespaces com escopo pode alcançar um namespace irmão quando os rótulos compartilham um prefixo textual (foo / foobar, 1 / 12) ou contêm % / _. No SQLite, a busca também igualava diferenças apenas de maiúsculas ASCII.Atualize o pacote checkpoint aplicável para 3.1.1 ou posterior. Teste prefixos irmãos, caracteres curinga, correspondência de sufixo e diferenças de caixa no backend de produção.
Store SQLite anterior à 3.1.1 com rótulos de namespace que diferem apenas por caixa ASCII.A busca vulnerável de descendentes usava LIKE sem distinção de caixa, enquanto operações exatas distinguiam maiúsculas de minúsculas.Atualize e adicione um teste de regressão para caixa se os rótulos puderem diferir nesse aspecto.
Rótulos UUID de tamanho fixo sem % nem _.O aviso diz que esse formato não é afetado: rótulos de tamanho fixo não podem ser prefixos uns dos outros.Confirme que todos os segmentos seguem essa invariável. Se os rótulos puderem variar ou conter curingas, considere a implantação afetada.
InMemoryStore.Não afetado: compara individualmente os elementos do namespace.Não é necessário atualizar por este CVE; mantenha verificações de propriedade do tenant no limite da aplicação.
Implantação hospedada do LangSmith.O padrão LANGGRAPH_STORE_BACKEND=python usa AsyncPostgresStore e está no escopo com um pacote afetado. O backend separado grpc recebeu uma correção equivalente.Verifique o backend configurado e a versão implantada; confirme a versão ou a atualização hospedada em vez de inferir exposição apenas pelo nome do produto.

Fluxo de Ataque Passo a Paso

Passo 1

Confira o backend e os rótulos

A implantação precisa usar langgraph-checkpoint-postgres ou langgraph-checkpoint-sqlite anterior à 3.1.1 e depender do namespace para separar usuários ou tenants. Rótulos com prefixos em comum ou com % e _ tornam o limite relevante.

Passo 2

Uma leitura normal com escopo é feita

Uma solicitação autenticada da aplicação pesquisa um namespace como foo. O chamador não precisa enviar um payload especial; o namespace comum é a entrada do comparador vulnerável.

Passo 3

O backend achata e compara por padrão

O Store junta os rótulos com pontos e usa um prefixo LIKE terminado em %. Sem exigir o separador, foo pode corresponder a foobar; caracteres de padrão nos rótulos também podem ampliar o resultado.

Passo 4

Itens de um namespace irmão podem aparecer

Quando a aplicação trata namespaces como limites entre tenants, a busca ou a listagem pode retornar itens armazenados de outro usuário. É um problema de confidencialidade em leitura, não SQL injection nem acesso de escrita.

Passo 5

Atualize e teste o isolamento

Atualize os dois pacotes aplicáveis para 3.1.1 ou posterior. Teste prefixos de namespaces irmãos, rótulos literais com % e _, sufixos e a sensibilidade a maiúsculas/minúsculas do SQLite usando tenants de teste separados.

Código-Fonte: Vulnerável vs. Seguro

O predicado vulnerável trata toda string que começa com o namespace achatado como descendente. A correção adiciona uma comparação por igualdade exata e exige um ponto literal antes dos segmentos descendentes; também escapa barra invertida, % e _ no trecho LIKE. O commit upstream também substitui os padrões de prefixo/sufixo de list_namespaces por uma correspondência consciente de segmentos e ajusta a busca SQLite. Este é um trecho do código, não um módulo substituto.

Trecho de origem: libs/checkpoint-postgres/langgraph/store/postgres/base.py

IMPLEMENTAÇÃO VULNERÁVEL
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
PATCH SEGURO E ROBUSTO
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 Verificação de Segurança para Engenharia

Fontes