Ataque a la cadena de suministro en Rust: crates comprometidos con malware de tiempo de compilación
El Proyecto Rust ha eliminado de crates.io versiones maliciosas de tres crates ampliamente utilizados, después de que una cuenta de mantenedor comprometida publicara versiones que incluían una dependencia con typo-squatting cuyo script de compilación descargaba y ejecutaba un payload remoto durante la compilación. Las versiones afectadas son arrayref 0.3.10, internment 0.8.7 y append-only-vec 0.1.9, todas publicadas desde la misma cuenta propietaria el 20 de agosto de 2026 y eliminadas entre 86 y 107 minutos después.
Debido a que el código malicioso se encontraba en el script de compilación de la dependencia inyectada, bastaba con compilar un proyecto que la resolviera para ejecutar el payload, sin necesidad de llamar a ninguna función de los crates afectados.
Se recomienda a los desarrolladores buscar en ~/.cargo/registry/cache los archivos de los crates eliminados y fijar arrayref en 0.3.9 o anterior, después de que el equipo de respuesta de seguridad de Rust desmarcara como yanked las versiones maliciosas durante la respuesta. No existe una versión parcheada, no se ha asignado un identificador CVE, y los avisos de RustSec para los tres crates no registran evidencia de que alguna versión maliciosa haya sido utilizada.
"Una nueva versión del crate arrayref se publicó con una dependencia directa de proc-macro1, que ejecutaría un script de compilación malicioso. Esta versión comprometida se publicó el 2026-08-20 y se eliminó aproximadamente 86 minutos después, sin evidencia de uso real", RUSTSEC-2026-0260.
The Hacker News se puso en contacto con el equipo de respuesta de seguridad de Rust para conocer la base de esa conclusión y el número de descargas de las versiones eliminadas, pero no había recibido respuesta al momento de redactar este artículo. El equipo de respuesta de seguridad de Rust declaró que recibió el informe de que el crate proc-macro1 era malicioso a las 07:15 UTC del 20 de agosto y verificó que el crate llevaba un script de compilación que descargaba un payload malicioso, en un aviso que acredita al equipo de investigación de Nextron Systems GmbH como descubridor y notificador inicial.
"No creemos que el autor de arrayref esté actuando maliciosamente, pero es probable que su computadora o credenciales estén comprometidas, y estamos intentando contactarlo", dijo el equipo de respuesta de seguridad de Rust.
The Hacker News confirmó a través de la API de crates.io el 21 de agosto que el único propietario listado de arrayref es el usuario 2402, David Roundy, registrado en octubre de 2009. No se ha revelado cómo se comprometió la cuenta. El equipo de respuesta de seguridad de Rust enumeró las versiones maliciosas que eliminó, con el tiempo que estuvieron en línea: arrayref@0.3.10 publicado a las 07:15:00Z y eliminado a las 08:41:40Z (86 minutos en línea); internment@0.8.7 publicado a las 07:34:07Z y eliminado a las 09:04:11Z (90 minutos); append-only-vec@0.1.9 publicado a las 07:37:49Z y eliminado a las 09:25:24Z (107 minutos); además, proc-macro1, proc-macro-en, aovine, arone, aronenao y tinymember (cualquier versión).
Cada versión comprometida añadía una sola línea en su manifiesto: una dependencia de proc-macro1, un typo-squat del ubicuo crate proc-macro2. El código fuente de proc-macro1 es una copia genuina de proc-macro2, por lo que las compilaciones se completaban con normalidad. El script de compilación reconstruye su host de payload y dirección de comando y control (C2) a partir de fragmentos base64 durante la compilación. Luego instala un verificador de certificados personalizado cuyos tres métodos de verificación devuelven éxito incondicionalmente, deshabilitando la validación TLS. Selecciona uno de cuatro payloads según el sistema operativo y la arquitectura de CPU.
En Unix y macOS escribe los bytes en /tmp/rust-setup, marca el archivo como ejecutable y lo lanza de forma desacoplada con la dirección C2 como primer argumento. En Windows escribe un script de PowerShell en %TEMP% y lo ejecuta oculto mediante un lanzador VBScript bajo wscript.exe, abandonando luego el proceso hijo, un paso comentado en el código fuente como para escapar del job object de Cargo y evitar que la compilación espere por él.
La entrega dependía de que la cuenta propietaria marcara como yanked las versiones 0.3.5 a 0.3.9 de arrayref en el mismo minuto que la publicación maliciosa, dejando la versión comprometida como la única que Cargo no advertiría, según el informe presentado a la base de datos de avisos de RustSec por el investigador que la encontró.
"Entrega: 0.3.5–0.3.9 están todas yanked bajo la cuenta propietaria, así que la advertencia de cargo de 'considerar actualizar a una versión que no esté yanked' es el señuelo. Así es como lo encontré", dijo el reportero, usuario de GitHub jhobern.
The Hacker News encontró a través de la API de crates.io el 21 de agosto que arrayref tiene 245,385,500 descargas totales y 53,905,601 en los 90 días hasta el 20 de agosto, y que 403 crates distintos en crates.io dependen de él. También verificamos cada salto de la cadena de dependencias mencionada en el informe contra el índice de crates.io el 21 de agosto: winit requiere sctk-adwaita ^0.10.1, que requiere tiny-skia ^0.11, que requiere arrayref ^0.3.6. Cada requisito en esa cadena es un rango caret en 0.3.x, y un rango caret en 0.3.x acepta 0.3.10. La misma comprobación encontró que blake3 declaraba arrayref como dependencia hasta la versión 1.8.6 y no en 1.8.7, publicada a las 09:09 UTC del 20 de agosto, y que blake2b_simd y blake2s_simd eliminaron la misma dependencia en versiones publicadas a las 09:25 y 09:26 UTC de esa mañana.
El implante de segunda etapa se comunica por HTTPS POST a la ruta /49890878, persiste mediante una clave de registro Run en Windows, un LaunchAgent en macOS y un servicio de usuario systemd en Linux, y admite cuatro comandos que cubren terminación, reconfiguración de C2, instalación de persistencia y descarga y ejecución de más scripts, según Wiz, que dijo que roba credenciales de navegador de Chrome, Brave y Edge consultando bases de datos SQLite de inicio de sesión.
El análisis del investigador de Nextron indica que el payload de Windows analizado consulta solo las columnas origin_url y username_value y no extrae directamente password_value, pero ese análisis cubrió solo el payload de Windows, con los payloads de Linux y macOS con hash y no analizados. El mismo análisis señala que el crate puede ser activado por cargo build, cargo check y cargo test.
Indicadores de compromiso (IoCs)
- Red: 23.254.165.112:9089 (host de payload), 23.254.165.112:443 (C2), hwsrv-798836.hostwindsdns.com
- Archivos: /tmp/rust-setup, %TEMP%\rust-setup.ps1, %TEMP%\rust-setup-launch.vbs
- Binarios: rust-crate_0.1.0, _0.2.0, _0.3.0, _0.4.0
- Cuentas: dtolney (crates.io id 438608), impostor; droundy, propietario legítimo, presuntamente comprometido
- Correo: rchaitm@gmail.com, metadatos de autor falsificados
Wiz dijo que la infraestructura se superpone sustancialmente con ataques recientes de la cadena de suministro de Corea del Norte, mencionando el compromiso de npm de Mastra y el compromiso de axios. Microsoft evalúa con alta confianza que la actividad de Mastra es atribuible a Sapphire Sleet, y Google Threat Intelligence Group (GTIG) atribuyó el compromiso de axios a un actor que ahora rastrea como MIDNIGHT NEPTUNE, anteriormente conocido como UNC1069. Ningún proveedor ha atribuido el incidente de crates.io a un actor nombrado.
"Si bien las versiones maliciosas de axios se eliminaron del registro npm dentro de las tres horas posteriores a su lanzamiento, se estima que el alcance del compromiso es amplio, ya que el paquete tiene más de 100 millones de descargas semanales", dijeron GTIG y Mandiant en un informe del 30 de julio que recomendaba ventanas de enfriamiento para activos de terceros recién publicados.
Cargo no tiene un equivalente incorporado. Una solicitud de extracción que estabiliza un ajuste de global-min-publish-age, que retendría dependencias más jóvenes que una edad configurada, entró en su período de comentarios final el 18 de agosto, dos días antes del ataque, y seguía abierta y sin fusionar al 21 de agosto. GitHub implementó un enfriamiento similar por defecto para Dependabot en julio. En un caso de septiembre de 2025, dos crates maliciosos que suplantaban una biblioteca de registro se ejecutaban solo en tiempo de ejecución, una distinción que crates.io señaló en ese momento.