
# Encontrei uma Vulnerabilidade Zero-Day no langchain — Veja Como Foi
Como uma API legada esquecida em um dos frameworks mais populares de IA expôs silenciosamente milhões de aplicações a leituras arbitrárias de arquivos.
Existe uma certa sensação quando uma prova de conceito funciona na primeira tentativa. Não é exatamente empolgação — é mais uma percepção lenta e desconfortável de que algo real acabou de acontecer. Foi assim que me senti quando executei minha configuração de teste contra load_prompt_from_config() e vi o conteúdo de um arquivo que não deveria ter permissão de ler sendo impresso diretamente no meu terminal.
Esta é a história do CVE-2026-34070: uma vulnerabilidade de path traversal em langchain-core, agora corrigida na versão 1.2.22.
Se você construiu qualquer coisa com IA nos últimos anos, quase certamente já usou o LangChain. Ele é o tecido conjuntivo da stack moderna de IA — o framework que conecta modelos de linguagem, armazenamentos de vetores, ferramentas e gerenciamento de prompts em aplicações coerentes. Com mais de 130 mil estrelas no GitHub e adoção em tudo, desde projetos de fim de semana até implantações empresariais, uma vulnerabilidade aqui não fica contida.
Eu estava fazendo uma revisão de código do subsistema de prompts quando algo chamou minha atenção: um módulo chamado langchain_core/prompts/loading.py. Ele estava carregando arquivos do disco com base em valores extraídos diretamente de dicionários de configuração desserializados. Sem validação. Sem sanitização de caminhos. Apenas .
open(path)Continuei lendo.
Três funções internas estavam no centro disso:
_load_template() — lê arquivos referenciados por template_path, suffix_path e prefix_path_load_examples() — lê arquivos referenciados pela chave examples quando ela é uma string_load_few_shot_prompt() — lê arquivos referenciados por example_prompt_pathAs verificações de extensão de arquivo existiam. .txt para templates. .json, .yaml, .yml para exemplos. Mas não havia nada impedindo que esses caminhos fossem absolutos (/etc/passwd) ou baseados em traversal (../../../../home/user/.ssh/). O filtro de extensão dava uma falsa sensação de segurança — apenas significava que um atacante precisava escolher a extensão certa, não que o ataque estava bloqueado.
Essas funções são todas alcançáveis por meio de duas APIs públicas: load_prompt() e load_prompt_from_config().
A versão mais simples era assim:
from langchain_core.prompts.loading import load_prompt_from_config
config = {
"_type": "prompt",
"template_path": "/tmp/secret.txt",
"input_variables": [],
}
prompt = load_prompt_from_config(config)
print(prompt.template) # conteúdo de /tmp/secret.txt, impresso limpo
É isso. Passe um caminho absoluto, receba o conteúdo do arquivo de volta embrulhado em um PromptTemplate. Sem autenticação. Sem privilégios especiais. Se você puder influenciar o dicionário de configuração, poderá ler arquivos.
O directory traversal funcionava igualmente limpo:
config = {
"_type": "prompt",
"template_path": "../../etc/secret.txt",
"input_variables": [],
}
A variante JSON/YAML era argumentavelmente mais perigosa por causa dos tipos de arquivos que podia alcançar:
config = {
"_type": "few_shot",
"examples": "../../../../.docker/config.json",
"example_prompt": {
"_type": "prompt",
"input_variables": ["input", "output"],
"template": "{input}: {output}",
},
"prefix": "",
"suffix": "{query}",
"input_variables": ["query"],
}
prompt = load_prompt_from_config(config)
.docker/config.json contém suas credenciais do Docker Hub. ~/.azure/accessTokens.json tem seus tokens do Azure. Manifestos Kubernetes, configurações de CI/CD, configurações internas de aplicações — qualquer coisa com a extensão certa em qualquer lugar do sistema de arquivos estava em jogo.
A pontuação CVSS veio em 7.5 Alta, com um vetor de AV:N/AC:L/PR:N/UI:N — acessível pela rede, baixa complexidade, sem privilégios, sem necessidade de interação do usuário.
A pontuação é limitada abaixo de 9+ porque a verificação de extensão de arquivo realmente limita quais arquivos podem ser lidos. Mas 7.5 ainda subestima o impacto no mundo real em certos padrões de implantação.
Pense em onde isso aterrissa em produção:
load_prompt_from_config(), todo usuário é um potencial atacante.Nesses ambientes, a limitação de "restringido por extensão de arquivo" importa muito menos. Um atacante pode simplesmente mirar arquivos que sabe que existem com a extensão certa. Em uma instância de nuvem típica: requirements.txt, config.yaml, .env.yaml, arquivos de segredos montados com extensões .json — a lista é longa.
As funções afetadas são descritas no advisory como "APIs legadas não documentadas". Elas são anteriores ao sistema de serialização atual do langchain_core.load (dumpd/dumps/load/loads), que usa um modelo baseado em allowlist e não realiza leituras do sistema de arquivos.
As novas APIs existem. São melhores. Mas o código antigo nunca foi limpo — apenas ficou lá, alcançável, sem validação, esperando.
Este é um padrão que vale a pena observar. Em projetos open-source de movimento rápido, especialmente aqueles que cresceram tão rapidamente quanto o LangChain, a dívida técnica se acumula nos cantos. Código legado que "nunca foi realmente destinado a usuários" não recebe o mesmo escrutínio que a superfície principal da API. Mas ainda é chamável. Ainda está no pacote. E se lê arquivos do disco, é uma vulnerabilidade potencial.
O patch chegou no langchain-core 1.2.22. A correção adiciona validação de caminho que rejeita tanto caminhos absolutos quanto sequências de traversal .. antes que qualquer arquivo seja aberto. Uma porta de escape — allow_dangerous_paths=True — está disponível para aplicações que genuinamente precisam ler de caminhos confiáveis, com o reconhecimento explícito de que o chamador está optando pelo risco.
As APIs legadas também foram formalmente descontinuadas com este lançamento. Serão removidas completamente na versão 2.0.0. Se você está usando load_prompt() ou load_prompt_from_config() em qualquer lugar, migre para os equivalentes do langchain_core.load agora, em vez de esperar pela mudança disruptiva.
Atualize imediatamente:
pip install --upgrade langchain-core
Verifique se você está na 1.2.22 ou mais recente:
python -c "import langchain_core; print(langchain_core.__version__)"
Se você está construindo com LangChain, uma auditoria rápida vale a pena:
load_prompt e load_prompt_from_config no seu código. Se aparecerem, verifique o que está sendo passado para eles..txt, .json ou .yaml existem nas suas instâncias e o que eles contêm.Bugs de segurança em infraestrutura de IA vão importar mais, não menos, à medida que esses sistemas lidam com cargas de trabalho mais sensíveis. A equipe do LangChain respondeu bem — a correção é limpa, o caminho de descontinuação é claro e a documentação do advisory é completa.
Mas é um bom lembrete de que a superfície de ataque de uma aplicação de IA não é apenas o modelo. É cada biblioteca na stack, cada função legada que nunca foi limpa, cada lugar onde "o usuário provavelmente não vai passar entrada não confiável aqui" acabou sendo uma suposição em vez de uma garantia.
Leia o código. Especialmente as partes antigas.
CVE-2026-34070 foi atribuído a esta vulnerabilidade. O advisory completo está disponível no LangChain GitHub Security Advisory.