Una ilustración abstracta generada sobre un fondo azul marino oscuro: una pila de cinco bandejas de memoria finas de color cian vistas en corte, cada una con filas de pequeños bloques grises, con un pequeño cubo ámbar deslizado entre la tercera y la cuarta bandeja; desde ese cubo, un fino filamento ámbar de partículas se arquea hacia la derecha a través de un vacío oscuro en dirección a tres pequeños nodos de color rojo anaranjado dispuestos en triángulo. Detrás de las bandejas, cuelgan etiquetas grises tenues de un llavero mediante finos bucles. No aparecen textos, personas ni logotipos de organizaciones. El logotipo de OrcaRouter está compuesto en la esquina inferior derecha.
AI Safety Incidents

sckit: Los paquetes de memoria de IA de MemTensor fueron modificados con puertas traseras para robar credenciales y prompts de agentes

Autor

Rowan Sterling

Fecha de publicación

Últimos modelos · 20Ver todos los modelos →
Benchmarks: Artificial Analysis · actualizado a diario
Volver a todas las publicaciones

Cuatro versiones de MemTensor publicadas el 23 de septiembre de 2026 incluían el mismo implante Go despojado, y cada una era la versión más reciente en su registro mientras estuvo activa. De npm, @memtensor/memos-cloud-openclaw-plugin se publicó como 0.1.21 a las 02:23 UTC, 0.1.23 a las 03:49 y 0.1.25 a las 04:36; en PyPI, MemoryOS se publicó como 2.0.34 a las 05:25. Las cuatro incluían sckit, que se inicia cuando arranca el gateway del agente OpenClaw, se vuelve a iniciar en cada recuperación de memoria —se le pasa el texto del prompt del usuario en una variable de entorno— y, en el paquete de Python, se inicia con una simple importación del módulo memos. Luego recorre el directorio home en busca de secretos de npm, PyPI, GitHub, GitLab, AWS, Vault y SSH y envía lo que encuentra a servidores bajo skyleen[.]fr. Socket, StepSecurity, SafeDep y Aikido documentaron el compromiso de forma independiente ese mismo día, y ninguno de ellos informó de evidencia de que el implante se hubiera ejecutado en un host real. El Orca AI Incident Archive conserva esta entrada íntegra, junto con todos los demás incidentes de cadena de suministro que ha registrado, y cada registro tiene su propio grado de confianza y estado de daño.

Cuatro lanzamientos, y un informe público de errores en medio de ellos

MemOS es el framework de memoria de código abierto de MemTensor para agentes LLM, y el paquete npm es el conector que permite que un entorno de ejecución de agentes OpenClaw lea y escriba en un servicio de memoria alojado; StepSecurity señala que el mismo paquete también declara puntos de integración para los entornos de ejecución Clawdbot y Moltbot. Socket midió el repositorio en alrededor de 11.500 estrellas y 1.100 forks cuando lo publicó. Esa posición es la razón por la que el compromiso atrajo cuatro investigaciones separadas: como lo expresó StepSecurity, esto "coloca el plugin dentro de un proceso que maneja habitualmente entrada de usuario y puede heredar credenciales valiosas". Las personas expuestas son las que instalaron cualquiera de los dos paquetes —desarrolladores en sus propias máquinas, y ejecutores de CI y contenedores que solo ejecutaron una suite de pruebas.

La secuencia de npm es la parte más clara del registro porque las marcas de tiempo del registro son públicas y varias empresas las capturaron de forma independiente. El informe de Socket y la cronología de SafeDep coinciden al minuto: 0.1.21 a las 02:23:04, 0.1.22 a las 03:45:44, 0.1.23 a las 03:49:20, 0.1.24 a las 04:33:30 y 0.1.25 a las 04:36:58. Las versiones 0.1.22 y 0.1.24 estaban limpias — Socket dice que coincidían con 0.1.20 salvo por las cadenas de versión — y el payload volvió tres minutos y medio después de cada una de ellas.

El salto de tamaño es la señal. Socket midió 0.1.20 en unos 272 KB desempaquetado y 0.1.21 en 43,6 MB, porque las versiones maliciosas incluían seis binarios de plataforma enlazados estáticamente de unos 7,4 MB cada uno. PyPI muestra el mismo patrón: la rueda 2.0.34 era de 19.201.772 bytes frente a 951.210 de la 2.0.33, según Socket.

A las 04:17 UTC —dieciséis minutos antes de la versión limpia 0.1.24 y diecinueve antes de que la carga útil volviera como 0.1.25—, un usuario de GitHub llamado omeridel abrió el issue #173 en el repositorio del plugin, titulado «Versiones maliciosas 0.1.21 y 0.1.23 publicadas en npm: el token de publicación parece comprometido». El issue señala que 0.1.23 era entonces la etiqueta más reciente, que ninguna de las dos versiones coincidía con ningún commit ni etiqueta del repositorio y que el commit legítimo más reciente estaba fechado el 14 de agosto. Sigue abierto sin comentarios de los mantenedores a fecha de 26 de octubre de 2026.

A self-built HTML card headed 'Supply chain, 23 September 2026, all times UTC', titled 'Four and a half hours on npm and PyPI', subtitled 'Each malicious release was the registry's newest version while it was live'. Nine rows, each with a time, an event, a detail and a status chip: 00:48 attacker branch first pushed, pipeline; 02:23 npm 0.1.21 published, 43.6 MB unpacked up from 272 KB, malicious; 03:17 MemOS commit b52958f, six sckit binaries and a CI token stealer, malicious; 03:45 npm 0.1.22 published, matches 0.1.20 apart from version strings, clean; 03:49 npm 0.1.23 published, payload restored three minutes later, malicious; 04:17 GitHub issue 173 filed, disclosure; 04:33 npm 0.1.24 published, clean again and the latest tag for three minutes; 04:36 npm 0.1.25 published, payload back and this one takes the latest tag, malicious; 05:25 PyPI MemoryOS 2.0.34, 19.2 MB wheel against 951 KB in 2.0.33, malicious. A footer reads 'Timestamps from Socket and SafeDep, which agree to the minute. Sizes from Socket.' The OrcaRouter logo is composited in the bottom-right corner.

Qué hace sckit una vez que el paquete está cargado

Ninguno de los dos paquetes utilizó un hook de instalación, por lo que el consejo habitual sobre --ignore-scripts no era aplicable. El análisis de StepSecurity de la variante de npm describe un archivo nuevo, lib/sckit.js, que exporta un lanzador que el código existente de inicio y de recuperación de memoria del complemento importa y llama. Al iniciarse, genera un proceso separado .sckit/<os>-<arch>/sckit con stage0 --config64 y el entorno completo del proceso padre; al recuperar la memoria, hace lo mismo y pasa el prompt del usuario despojado mediante una variable de entorno llamada SCKIT_EVENT_TEXT. Socket expuso la consecuencia sin rodeos: por lo tanto, el binario se ejecuta de nuevo en cada recuperación.

La variante de PyPI es más corta y, en la práctica, más difícil de evitar. Socket descubrió que memos/log.py llama a una función de activación dentro de memos/_stage0.py cuando se configura el registro, que 149 módulos llaman al registrador a nivel de módulo y que, por lo tanto, una importación simple del módulo memos basta para iniciar la carga útil una vez por proceso. El análisis de StepSecurity del mismo paquete fue puramente estático: no lo instaló, importó, compiló ni ejecutó.

El alcance de la recopilación es todo el directorio de inicio. SafeDep enumera la raíz del inventario como $HOME y los archivos objetivo como .npmrc, .pypirc, .git-credentials, .netrc, id_rsa, id_ecdsa, id_ed25519, .vault-token, msal_token_cache, access_tokens.json y access_tokens.db, además de variables de entorno cuyos nombres contienen token, secreto, contraseña, clave de API o URL de base de datos, además de formatos de token reconocidos para GitHub, GitLab, npm, PyPI, Hugging Face, Slack, Stripe, AWS y SendGrid. Los registros OSV de los dos paquetes, MAL-2026-16476 para npm y MAL-2026-16475 para PyPI, describen la misma lista de archivos y añaden que el protocolo de mando y control utiliza CBOR, intercambio de claves X25519 y XChaCha20-Poly1305, con arrendamientos firmados y módulos entregados en tiempo de ejecución; por lo tanto, nunca se observó el contenido de los módulos, solo el cargador que los recupera.

Dos detalles determinan lo que un defensor todavía puede recuperar. El binario contiene rutinas de autoborrado llamadas scheduleSelfDelete y deleteExecutable, según el registro de OSV, y por eso la recomendación es buscar artefactos de procesos y de red en lugar de archivos. Y la versión 0.1.25 añadió lib/tls-trust.js, que establece SSL_CERT_FILE en un archivo de autoridad de certificación incluido con 145 certificados en sistemas Linux mínimos, según StepSecurity — una corrección destinada a hacer que su propio tráfico funcione en contenedores que carecen de un almacén de confianza del sistema.

A generated abstract illustration on a dark navy field: at left, a dim cyan isometric tree of folders, several leaves carrying small grey key and badge silhouettes; from those keys a cluster of amber threads lifts away, braids into one bright cord and runs right through a narrow vertical cyan gateway frame that carries an amber keyhole, toward three small red-orange receivers with faint pulse rings on the far right. No text, people or organisation logos appear. The OrcaRouter logo is composited in the bottom-right corner.

El pipeline de lanzamiento era la forma de entrar.

La reconstrucción de SafeDep es el relato más detallado del acceso inicial y apunta a GitHub Actions en lugar de a una contraseña de registro robada. Entre 00:48 y 02:03 UTC, una cuenta de GitHub que operaba como Memtensor-AI creó, subió y eliminó una rama llamada sc/release-0.1.21-20260922-cloud cinco veces. El commit 9b97ec6 modificó el script de flujo de trabajo .github/scripts/validate-release-confirmation.mjs para que añadiera un valor BASH_ENV a $GITHUB_ENV, lo que hizo que los pasos posteriores de shell no interactivo cargaran mediante source un sckit-publish-bridge.sh proporcionado por el atacante antes de ejecutar sus propios comandos. Ese puente comprobaba el nombre del paquete y el tiempo de espera de 150 segundos del paso de publicación, llamaba al recolector de tokens con NPM_TOKEN o NODE_AUTH_TOKEN, se eliminaba a sí mismo y salía con 1 — así que la publicación falló después de que se hubiera tomado el token. La primera versión maliciosa de npm apareció veinte minutos después del último push a la rama.

La ruta de PyPI utilizó el mismo truco contra un canal diferente. SafeDep informa que la etiqueta v2.0.34 apuntaba a commits sin firmar que no estaban en main, y que el commit b52958f, atribuido a "MemTensor CI Review", añadió los seis binarios, un cargador de Python y un backend de compilación personalizado llamado sckit_poetry_build. Ese backend escribió un BASH_ENV que apuntaba a _pypi_bridge.sh en $GITHUB_ENV; el puente solo actuaba dentro del envoltorio de subida de twine, obtenía un índice firmado del host skyleen[.]fr, verificaba un emisor con una implementación de Ed25519, imprimía una línea marcadora, eliminaba la contraseña de subida y salía sin subir nada. Unas dos horas más tarde, el commit 41bf5c7 eliminó esa llamada con el mensaje "chore: allow native PyPI upload [skip ci]", la etiqueta se eliminó y se volvió a crear en menos de diez segundos, y la subida a PyPI se produjo 62 segundos después. SafeDep interpreta el primer commit como una ejecución de captura de tokens y el segundo como la ejecución que permitió que el propio flujo de trabajo de MemTensor compilara y publicara el paquete malicioso con el token real del proyecto.

No todas las versiones coinciden en este punto. Socket observó que las versiones de npm provenían de la misma cuenta de npm que versiones legítimas anteriores y carecían de un gitHead, lo que interpretó como indicio de que no fueron producidas por el CI del proyecto, y declaró que no podía confirmar cómo el atacante obtuvo acceso de publicación. SC Media, al informar sobre los hallazgos de Socket el 24 de septiembre, llegó a la misma inferencia hacia un compromiso de la cuenta. Las dos versiones coinciden en que las credenciales de publicación se tomaron del canal de publicación y difieren en cómo se produjo el propio artefacto de npm; nadie ha publicado los registros del flujo de trabajo, porque la API de Actions de GitHub no mostró ejecuciones después del 7 de septiembre y SafeDep infiere que los registros se eliminaron. Cómo obtuvo la cuenta de Memtensor-AI acceso de push en primer lugar es desconocido en ambas versiones; SafeDep considera probable pero no confirmado que se haya usado un token de cuenta robado.

Establecido, inferido y ausente

El grado de confianza del registro es A y no está en disputa, lo cual vale la pena precisar, porque la certeza se refiere a lo que se publicó y no a lo que hizo.

• Establecido: el contenido de los cuatro artefactos, reconstruido mediante análisis estático en Socket, StepSecurity y SafeDep; los tiempos de publicación en npm y la última etiqueta en 0.1.25; el aumento de tamaño en ambos ecosistemas; los commits, etiquetas e historial de ramas en los dos repositorios; la infraestructura skyleen[.]fr y los identificadores de campaña cloud-openclaw-semi-nuclear y memos-semi-nuclear; y la configuración del payload, que expira el 22–23 de octubre de 2026 según Socket y SafeDep.

• Inferido: que la herramienta se escribió con la ayuda de un modelo de lenguaje, lo cual SafeDep afirma directamente y denomina una inferencia; y que los tokens de publicación robados estaban pensados para reutilizarse, lo cual la cadena de canal de la configuración —"exact-ref-one-use-NPM_TOKEN"— respalda, pero no prueba.

• No establecido: quién era el atacante; si alguna copia de sckit se ejecutó alguna vez fuera de un sandbox; si alguna credencial salió de un host; si algún prompt escrito en un agente OpenClaw llegó al atacante; y si algún paquete downstream se volvió a publicar. Socket y StepSecurity trabajaron ambos de forma estática, y StepSecurity afirma que en su análisis no se observó ningún proceso ejecutado, ninguna transmisión de secretos, ninguna exfiltración exitosa, ninguna instalación de flujo de trabajo y ninguna publicación adicional de paquetes.

Esa brecha es la razón por la que el archivo registra este incidente con el daño real marcado como falso. La exposición es real y amplia —a cualquiera que haya instalado una versión afectada se le indica que trate el host como comprometido—, pero ninguna de las cuatro empresas investigadoras ha registrado daño, en el sentido de una credencial usada de forma demostrable o un sistema alcanzado de forma demostrable.

A self-built HTML card headed 'What the record supports', titled 'Four investigating firms, no confirmed victim', subtitled 'Socket, StepSecurity, SafeDep and Aikido documented the same four artefacts on 23 September 2026'. The left column, headed 'Established by static analysis', lists: four malicious releases, npm 0.1.21, 0.1.23 and 0.1.25 and PyPI MemoryOS 2.0.34; one implant, the same stripped Go binary sckit in all four; the publish window 02:23 to 05:25 UTC with 0.1.25 tagged latest; package growth from 272 KB to 43.6 MB on npm and 951 KB to 19.2 MB for the PyPI wheel; six builds per package for Linux, macOS and Windows on amd64 and arm64; collection scoped to the whole home directory across registry, source-control, cloud, Vault and SSH secrets; exfiltration to servers under skyleen[.]fr; and OSV tracking as MAL-2026-16476 and MAL-2026-16475. The right column, headed 'Not established', lists: the attacker's identity; how Memtensor-AI obtained push access; whether any copy ever executed outside static analysis; whether a stolen secret reached the attacker; whether any prompt text was received; and whether any downstream package was republished. A footer reads 'Archive classification for this record: incident, severity high, confidence A, real harm false.' The OrcaRouter logo is composited in the bottom-right corner.

El gusano que nunca se vio propagarse

Los binarios contienen más que un stealer. SafeDep enumera funciones llamadas recursivePublish, prepareRemoteNode, prepareRemotePython y prepareRemoteWorkflow, además de una plantilla integrada de GitHub Actions que se activa al hacer push y la capacidad de escribir un archivo de flujo de trabajo llamado runtime-update.yml en repositorios a los que el implante puede acceder. Socket encontró cadenas sobre la codificación de manifiestos de paquetes y la instalación de archivos de repositorio, y evaluó que los binarios podrían ser capaces de volver a publicar paquetes usando tokens de registro robados.

Eso es un diseño de gusano. No es un gusano que se haya observado funcionando. StepSecurity no encontró pruebas de que la lógica se haya utilizado alguna vez para propagarse, y la nota de investigación de Cloud Security Alliance del 25 de septiembre interpreta la capacidad como un potencial limitado de autopropagación, en lugar de un comportamiento de gusano confirmado. Varios medios describieron el caso como el primer gusano de la cadena de suministro dirigido a la infraestructura de memoria de agentes de IA; la descripción es justa como afirmación sobre el diseño, y los informes no la respaldan como afirmación sobre lo que ocurrió.

¿Qué cambió después?

Los registros se limpiaron ese mismo día. Según una comprobación del 26 de octubre de 2026, los metadatos del paquete npm ya no incluyen 0.1.21, 0.1.23 ni 0.1.25 entre sus versiones, la etiqueta latest apunta a 0.1.24 y el paquete se modificó por última vez a las 11:53 UTC del 23 de septiembre. Todavía hay dos dist-tags inusuales asociados —clean-inverse-0-1-23, que apunta a 0.1.22, y clean-inverse-0-1-25, que apunta a 0.1.24—, lo que refleja las dos versiones limpias que interrumpieron brevemente las maliciosas. En PyPI, MemoryOS 2.0.34 ya no está y la versión más reciente es la 2.0.33, subida el 3 de septiembre de 2026; no ha habido ninguna otra publicación en PyPI en las siete semanas transcurridas desde entonces.

Lo que no ha cambiado es la versión pública del proyecto. El repositorio no enumera ningún aviso de seguridad, la incidencia de GitHub de las 04:17 del día del incidente sigue abierta y sin respuesta, y ninguno de los reportes examinados aquí cita una declaración de MemTensor ni de OpenClaw. Ninguno de los paquetes maliciosos llevaba una atestación de procedencia, lo que, según señala SafeDep, eliminó la única señal de que los artefactos se habían construido a partir de un commit inesperado.

La respuesta que sí existe está del lado de la detección: StepSecurity añadió los dominios de comando y control skyleen[.]fr a su lista de bloqueo global, y los dos paquetes están registrados en OSV como MAL-2026-16476 y MAL-2026-16475.

Si se instaló una versión afectada

La guía de Socket es la más estricta y la más sencilla: si se cargó o importó cualquiera de las versiones enumeradas, considera que ese host está comprometido, incluidos los runners de CI y los contenedores que solo ejecutaron pruebas. Los pasos concretos en los que coinciden las cuatro empresas:

• Elimine el paquete y fíjelo a una versión limpia — npm 0.1.20, PyPI 2.0.33. StepSecurity advierte que su análisis no estableció una línea base limpia de PyPI, mientras que SafeDep y SC Media coinciden en señalar 2.0.33 como la última versión buena.

• Busque la línea de comandos del proceso, ya que el ejecutable puede eliminarse a sí mismo: sckit stage0 --config64, y la variable de entorno SCKIT_EVENT_TEXT.

• Elimine los directorios de estado ~/.openclaw/.cache/runtime y ~/.memos/.cache/runtime, y revise los repositorios en busca de un flujo de trabajo runtime-update.yml inesperado o de directorios .sckit/.

• Rota cada credencial accesible desde el directorio home y el entorno del proceso, desde una máquina limpia: npm, PyPI, GitHub, GitLab, AWS, Vault, SSH, Hugging Face, Slack, Stripe y SendGrid, así como cualquier valor de .env. Los tokens de registro y de control de código fuente van primero.

• Revisa las publicaciones de tus propios paquetes, por si se usó un token de publicación robado para distribuir versiones que no escribiste.

• Bloquea skyleen[.]fr y sus subdominios, y consulta los registros de salida desde el 23 de septiembre.

• Trate cualquier prompt o secreto pegado que haya pasado por el plugin mientras estaba activo como expuesto. Esta es la parte del incidente específica de la memoria del agente: el implante no necesitaba extraer una transcripción, porque la transcripción se le entregaba en cada recuperación.