
Análisis técnico de vulnerabilidad y prueba de concepto para CVE-2026-47630, un dlopen arbitrario a través de TRITON_BATCH_STRATEGY_PATH en NVIDIA Triton Inference Server que permite la ejecución de código nativo, con orientación sobre detección y mitigación.
dlopen arbitrario mediante TRITON_BATCH_STRATEGY_PATHRecorrido de ruta absoluta en el cargador personalizado de estrategias de batching de triton-inference-server/core. Un parámetro de configuración del modelo se pasa sin validar a dlopen(RTLD_NOW | RTLD_LOCAL), por lo que cualquiera que pueda influir en el config.pbtxt de un modelo obtiene ejecución de código nativo dentro del proceso del servidor Triton en el momento de la carga del modelo.
El reconocimiento de NVIDIA en el boletín 5865 dice textualmente: CVE-2026-47630: s1ko.
Triton acepta un parámetro por modelo TRITON_BATCH_STRATEGY_PATH procedente del config.pbtxt del modelo. Hasta la versión 26.05, el valor se trataba como una ruta de archivo arbitraria y se pasaba sin modificar a dlopen. No había comprobación de contención, ni lista blanca, ni verificación de firma o hash. Se aceptaban rutas absolutas, secuencias de traversal y enlaces simbólicos.
RTLD_NOW resuelve todos los símbolos de inmediato y ejecuta las rutinas __attribute__((constructor)) / .init_array del objeto antes de que dlopen retorne. Por tanto, la ejecución es incondicional a una carga exitosa: ninguno de los puntos de entrada TRITONBACKEND_ModelBatch* necesita existir para que la carga útil se ejecute, y lo hace con los privilegios del proceso de Triton (frecuentemente root en los contenedores NGC).
src/backend_model.cc — la entrada del atacante llega a batch_libpath, validada solo por existencia:
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());
}
}
Llamativamente ausente está cualquier invocación a IsChildPathEscapingParentPath, que Triton ya aplicaba a las rutas de etiquetas y a las rutas de bibliotecas de backend en otras partes del mismo archivo.
src/backend_model.cc — SetBatchingStrategy lo reenvía:
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 — el sumidero:
*handle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
Existen tres vías prácticas para controlar model_config.parameters():
config.pbtxt de su modelo coloca un .so en su propio directorio y apunta el parámetro hacia él. La carga útil se ejecuta con los privilegios del servidor, otorgando acceso a los pesos, secretos y GPU de todos los demás inquilinos.TRITONSERVER_ServerLoadModelWithParameters combinado con el prefijo documentado file:<rel-path> permite a un llamador con derechos de carga de modelos enviar config.pbtxt y el .so en una única petición y disparar la carga de inmediato. No se requiere acceso al sistema de archivos fuera de la API.dlopen bajo demanda.poc/ contiene el primitivo, reducido a lo que hace OpenLibraryHandle. Solo fuentes: compílelas usted mismo:
$ 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
La carga útil es inerte: añade una línea con el pid, uid, euid y cwd. Verificada en Debian 13, GCC 14.2, x86_64.
Para el disparador del lado de Triton, coloque el evil.so compilado junto a poc/config.pbtxt en el repositorio de modelos y cargue el modelo — auto-carga, --load-model, o POST /v2/repository/models/evil_model/load. En una versión afectada, el constructor se dispara durante SetBatchingStrategy, antes de cualquier búsqueda de símbolos de backend.
La carga es registrada por el propio Triton a nivel INFO:
Loading custom batching strategy library <path> for model <name>
En una compilación corregida, un intento rechazado aparece como Batching library path escapes model repository.
Cualquier valor de TRITON_BATCH_STRATEGY_PATH que sea absoluto, contenga .., o resuelva fuera del directorio del modelo merece una alerta independientemente de la versión. Una regla Sigma que cubre tanto la línea de registro como el parámetro de configuración está en detection/.
Señales complementarias:
config.pbtxt que porten un parámetro TRITON_BATCH_STRATEGY_PATH — la característica es rara en la práctica, por lo que su sola presencia ya es un filtro útil.openat/mmap de un .so fuera de la raíz del modelo por parte del proceso tritonserver (auditd, eBPF o Falco).Actualice a Triton Inference Server 26.06 o posterior. La corrección añade la comprobación de contención que faltaba en el cargador:
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.");
}
Cuando la actualización no sea posible de inmediato, controles compensatorios:
TRITON_BATCH_STRATEGY_PATH de todo config.pbtxt antes de que llegue al repositorio de modelos.--model-control-mode distinto de explicit, o autorización en los endpoints del repositorio) a menos que sea necesaria.tritonserver como un usuario sin privilegios con un montaje de solo lectura del repositorio de modelos, de modo que una carga exitosa tenga el menor radio de explosión posible.Mapeo: MITRE ATT&CK T1574.006 Hijack Execution Flow: Dynamic Linker Hijacking y 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 — consulte LICENSE.
| CVE | CVE-2026-47630 |
| Boletín de NVIDIA | 5865 (2026-08-18) |
| CWE | CWE-36 (Recorrido de ruta absoluta); reportado como CWE-114 / CWE-829 |
| CVSS v3.1 (NVIDIA) | 5.5 MEDIA — AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N |
| Afectados | Triton Inference Server 0.0 – 26.05 (Linux) |
| Corregido en | 26.06 |
| Reportado por | s1ko (github.com/s1ko, [email protected]) |
| Seguimiento del proveedor | Ticket 6139742 de NVIDIA PSIRT |
| Fecha | Evento |
|---|
| 2026-04-25 | Hallazgo principal de manejo de rutas en Triton reportado; NVIDIA PSIRT abre el ticket 6128799 |
| 2026-05-01 | Este hallazgo secundario confirmado y reportado; PSIRT abre el ticket 6139742 |
| 2026-05-28 | Cadencia de divulgación coordinada acordada con PSIRT |
| 2026-06 | La corrección se publica en Triton Inference Server 26.06 |
| 2026-08-18 | NVIDIA publica el boletín 5865, asignando CVE-2026-47630 y acreditando a s1ko |
| 2026-08-22 | Publicación de este análisis |