
Análise técnica de vulnerabilidade e prova de conceito para CVE-2026-47630, um dlopen arbitrário via TRITON_BATCH_STRATEGY_PATH no NVIDIA Triton Inference Server que permite execução nativa de código, com orientações de detecção e mitigação.
dlopen arbitrário via TRITON_BATCH_STRATEGY_PATHTraversal de caminho absoluto no carregador de estratégia de batching personalizado de
triton-inference-server/core. Um parâmetro de configuração de modelo é passado
sem validação para dlopen(RTLD_NOW | RTLD_LOCAL), portanto qualquer pessoa capaz de influenciar o
config.pbtxt de um modelo obtém execução de código nativo dentro do processo do servidor Triton
no momento do carregamento do modelo.
O reconhecimento da NVIDIA no boletim 5865 diz textualmente: CVE-2026-47630: s1ko.
O Triton aceita um parâmetro TRITON_BATCH_STRATEGY_PATH por modelo do
config.pbtxt do modelo. Até 26.05, o valor era tratado como um caminho de sistema de arquivos
arbitrário e passado sem modificação para dlopen. Não havia verificação de contenção,
lista de permissões nem verificação de assinatura ou hash. Caminhos absolutos,
sequências de traversal e symlinks eram todos aceitos.
RTLD_NOW resolve cada símbolo imediatamente e executa as rotinas
__attribute__((constructor)) / .init_array do objeto antes que dlopen
retorne. Portanto, a execução não depende de um carregamento bem-sucedido — nenhum dos
pontos de entrada TRITONBACKEND_ModelBatch* precisa existir para que o payload seja
executado, e ele é executado com os privilégios do processo Triton (frequentemente root
em contêineres NGC).
src/backend_model.cc — a entrada do atacante chega a batch_libpath, validada apenas
quanto à existência:
if (model_config.parameters().contains("TRITON_BATCH_STRATEGY_PATH")) {
batch_libpath = model_config.parameters()
.at("TRITON_BATCH_STRATEGY_PATH")
.string_value();
bool exists = false;
RETURN_IF_ERROR(FileExists(batch_libpath, &exists));
if (!exists) {
return Status(
triton::common::Error::Code::NOT_FOUND,
("Batching library path not found: " + batch_libpath).c_str());
}
}
Notavelmente, não há nenhuma chamada a IsChildPathEscapingParentPath, que o Triton
já aplicava a caminhos de labels e a caminhos de bibliotecas de backend em outras partes do mesmo
arquivo.
src/backend_model.cc — SetBatchingStrategy o encaminha:
Status TritonModel::SetBatchingStrategy(const std::string& batch_libpath)
{
std::unique_ptr<SharedLibrary> slib;
RETURN_IF_ERROR(SharedLibrary::Acquire(&slib));
RETURN_IF_ERROR(slib->OpenLibraryHandle(batch_libpath, &batch_dlhandle_));
src/shared_library.cc — o sink:
*handle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
Três rotas práticas para controlar model_config.parameters():
config.pbtxt do seu modelo coloca um .so no seu próprio diretório e aponta o
parâmetro para ele. O payload é executado com os privilégios do servidor, dando
acesso aos pesos, segredos e GPU de todos os outros inquilinos.TRITONSERVER_ServerLoadModelWithParameters
combinado com o prefixo de parâmetro documentado file:<rel-path> permite que um
chamador com direitos de carregamento de modelo envie config.pbtxt e o .so em uma
única solicitação e acione o carregamento imediatamente. Nenhum acesso ao sistema de arquivos
fora da API é necessário.dlopen sob demanda.poc/ contém a primitiva, reduzida ao que OpenLibraryHandle
faz. Apenas fontes — compile-as você mesmo:
$ cd poc && ./build.sh
$ gcc -O0 -o test_dlopen test_dlopen.c -ldl
$ ./test_dlopen ./evil.so
dlopen OK, handle=0x55d1779652c0
$ cat /tmp/triton_dlopen_rce_proof.log
[triton-dlopen-rce] constructor fired @ Fri May 1 09:56:56 2026
pid=240157 uid=1000 euid=1000 cwd=/opt/poc
O payload é inerte: ele acrescenta uma linha registrando pid, uid, euid e cwd. Verificado no Debian 13, GCC 14.2, x86_64.
Para o acionamento pelo lado do Triton, coloque o evil.so compilado ao lado de
poc/config.pbtxt no repositório de modelos e carregue o
modelo — auto-load, --load-model ou
POST /v2/repository/models/evil_model/load. Em uma versão afetada, o
construtor é disparado durante SetBatchingStrategy, antes de qualquer busca de símbolo
de backend.
O carregamento é registrado pelo próprio Triton em nível INFO:
Loading custom batching strategy library <path> for model <name>
Em uma versão corrigida, uma tentativa rejeitada aparece como
Batching library path escapes model repository.
Qualquer valor TRITON_BATCH_STRATEGY_PATH que seja absoluto, contenha .. ou
resolva fora do diretório do modelo merece alerta independentemente da
versão. Uma regra Sigma cobrindo tanto a linha de log quanto o parâmetro de configuração está
em detection/.
Sinais complementares:
config.pbtxt que contenham sequer um parâmetro TRITON_BATCH_STRATEGY_PATH
— o recurso é raro na prática, portanto a mera presença já é um filtro útil.openat/mmap de um .so fora da raiz do modelo pelo processo tritonserver
(auditd, eBPF ou Falco).Atualize para o Triton Inference Server 26.06 ou posterior. A correção adiciona a verificação de contenção que faltava ao carregador:
bool escapes{true};
RETURN_IF_ERROR(IsChildPathEscapingParentPath(
batch_libpath, localized_model_dir->Path(), &escapes));
if (escapes) {
return Status(
Status::Code::INVALID_ARG,
"Batching library path escapes model repository.");
}
Quando a atualização não for imediatamente possível, controles compensatórios:
TRITON_BATCH_STRATEGY_PATH de todos os config.pbtxt
antes que cheguem ao repositório de modelos.--model-control-mode diferente de
explicit, ou autorização nos endpoints do repositório) a menos que seja
necessário.tritonserver como um usuário sem privilégios com um mount de repositório de modelos
somente leitura, para que um carregamento bem-sucedido tenha o menor raio de
explosão possível.Mapeamento: MITRE ATT&CK T1574.006 Hijack Execution Flow: Dynamic Linker
Hijacking e
T1129 Shared Modules;
NIST SP 800-53r5 SI-7, CM-5, SC-18; CIS Controls v8 §2, §4.
triton-inference-server/core — https://github.com/triton-inference-server/coreMIT — veja LICENSE.
| CVE | CVE-2026-47630 |
| Boletim NVIDIA | 5865 (2026-08-18) |
| CWE | CWE-36 (Absolute Path Traversal); relatado como CWE-114 / CWE-829 |
| CVSS v3.1 (NVIDIA) | 5.5 MEDIUM — AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N |
| Afetados | Triton Inference Server 0.0 – 26.05 (Linux) |
| Corrigido em | 26.06 |
| Relatado por | s1ko (github.com/s1ko, [email protected]) |
| Rastreamento do fornecedor | NVIDIA PSIRT ticket 6139742 |
| Data | Evento |
|---|
| 2026-04-25 | Descoberta primária de manipulação de caminhos no Triton reportada; NVIDIA PSIRT abre o ticket 6128799 |
| 2026-05-01 | Esta descoberta secundária confirmada e reportada; PSIRT abre o ticket 6139742 |
| 2026-05-28 | Cronograma de divulgação coordenada acordado com o PSIRT |
| 2026-06 | Correção lançada no Triton Inference Server 26.06 |
| 2026-08-18 | NVIDIA publica o boletim 5865, atribuindo CVE-2026-47630 e creditando s1ko |
| 2026-08-22 | Este relatório foi publicado |