El 23 de septiembre de 2026 un atacante publicó versiones con robo de credenciales de dos paquetes de MemTensor: el plugin de OpenClaw en npm @memtensor/memos-cloud-openclaw-plugin (0.1.21, 0.1.23 y 0.1.25) y la librería MemoryOS en PyPI (2.0.34). Según los registros de malware de OSV y varios proveedores de seguridad, el payload corre cuando se carga el paquete, no al instalarlo, y busca credenciales de npm, PyPI, Git, nube y Hugging Face.
Tres semanas después las versiones maliciosas ya no figuran en los metadatos de los registros, pero la exposición pertenece a cada máquina que alguna vez cargó una. Acá va qué confirma más de una fuente, qué descansa en un solo proveedor y la semana de trabajo que correría.
1. Contexto: Qué Pasó el 23 de Septiembre de 2026
GitHub describe MemOS como un sistema operativo de memoria para LLMs y agentes de IA; MemoryOS es su paquete en PyPI y el plugin de npm lo conecta con OpenClaw, un asistente personal de IA de código abierto. No fue typosquatting: los nombres eran los reales. Según el registro de OSV, un atacante con permisos de escritura en el repositorio de GitHub subió commits maliciosos y un tag v2.0.34, y el propio workflow de release del proyecto construyó y subió el archivo a PyPI. En npm, la reconstrucción de SafeDep muestra cinco versiones en unas dos horas, alternando maliciosas y limpias.
Cronología, 23 de septiembre de 2026 (UTC; SafeDep, metadatos de registros, OSV)
No hay CVE para el compromiso, pero sí un rastro de advisories
Ninguno de los registros de OSV trae alias CVE. El plugin npm tiene un advisory de malware en GitHub (GHSA-mhjf-v53x-7p87: afectadas 0.1.21, 0.1.23, 0.1.25; sin versión parcheada) y el archivo de PyPI está cubierto por PYSEC-2026-3987 y MAL-2026-16475. No lo confundas con CVE-2026-75110 / GHSA-v9vw-ccqp-q298, un advisory de autenticación de MemOS de agosto, sin relación, que GitHub lista como sin revisar.
Consecuencia práctica: la pregunta no es ‘¿mi versión es vulnerable?’ sino ‘¿algo en esta máquina cargó alguna vez una de estas cuatro versiones?’. Semgrep dice que hay que tratar como comprometido cualquier host que cargó una versión afectada de npm o importó la de PyPI, incluso los runners de CI que solo corrieron tests.
2. Cuatro Implicaciones para Equipos con Memoria de IA y Plugins de Agentes
Estas son las cuatro consecuencias que cambian cómo trataría las dependencias de agentes, ordenadas por la frecuencia con que van a importar en una semana normal.
Nada corre al instalar, así que endurecer la instalación no alcanza
Import y arranque · SafeDep, Semgrep, OSV
Ninguno de los dos paquetes usa un hook de instalación. El lado Python arranca cuando la librería configura el logging al importarse; el lado npm arranca cuando el gateway de OpenClaw carga el plugin y de nuevo en cada recuerdo de memoria. --ignore-scripts y las allow-lists de scripts de instalación siguen siendo buena práctica, pero no habrían frenado esto.
Una capa de memoria vive al lado de tus prompts y tus secretos
Hook de recall · Semgrep, Socket, CSA
En npm, el hook de recall pasa el texto del prompt al binario por una variable de entorno (SCKIT_EVENT_TEXT). Todo lo que escribiste al agente mientras una versión afectada estaba cargada, claves pegadas incluidas, hay que tratarlo como expuesto. Es una cuestión de datos, además de rotar tokens.
La vía de entrada fue el camino de release
Workflow y tags · OSV, SafeDep, Semgrep
La 2.0.34 de PyPI la construyó el workflow del propio proyecto desde un tag sobre commits que nunca estuvieron en main. Los builds de npm salieron de la cuenta que publicó la 0.1.20, pero no traen gitHead ni tag que coincida. SafeDep considera que un token robado de la cuenta es la explicación más probable y no pudo confirmarlo.
Diseño tipo gusano: tu token robado es el incidente de otro
Propagación · OSV, Aikido, Semgrep
OSV y Aikido describen código que reutiliza tokens de publicación robados y escribe un workflow en repositorios alcanzables. Semgrep dice que no tiene evidencia de que este malware se haya propagado y Aikido no halló repos públicos comprometidos cuando escribió. Tratalo como una capacidad, y rotá para que nunca llegue a ser un hecho.
Triaje de solo lectura: encontrá los paquetes y lo que dejan atrás
Todo lo de abajo solo lee archivos y lista procesos; nada ejecuta los paquetes. Los indicadores (directorios de estado, nombre del proceso y dominio) salen de los registros de OSV y de SafeDep, no de un análisis mío.
# 1. Lockfiles, manifiestos y SBOMs en cada repo y caché de CI grep -rnEi 'memos-cloud-openclaw-plugin|memoryos' \ --include='package-lock.json' --include='pnpm-lock.yaml' --include='yarn.lock' \ --include='requirements*.txt' --include='poetry.lock' --include='uv.lock' \ --include='*.sbom.json' . # 2. Qué está instalado ahora mismo npm ls --all 2>/dev/null | grep -i memos-cloud-openclaw-plugin pip show MemoryOS 2>/dev/null | grep -i '^version' # 3. Artefactos del host que nombran los reportes ls -la ~/.openclaw/.cache/runtime ~/.memos/.cache/runtime 2>/dev/null pgrep -fl sckit # PowerShell: Get-Process sckit -ErrorAction SilentlyContinue # 4. Logs de DNS, proxy y egress desde el 23-09: skyleen.fr y subdominios grep -rniE 'skyleen\.fr' /var/log 2>/dev/null
Desinstalar no es limpiar
El advisory de malware de GitHub dice que eliminar el paquete puede no quitar lo que dejó, y recomienda rotar los secretos desde otra computadora. Semgrep y Socket suman: matá cualquier proceso sckit y borrá los directorios de caché de runtime. Si un host tenía tokens de publicación, lo reconstruiría desde una imagen limpia en vez de limpiarlo en el lugar.
3. Qué Hacer Esta Semana
Cinco días hábiles. Los días 1–2 te dicen si estuviste expuesto; los días 3–4 asumen que sí; el día 5 hace más difícil el próximo.
☀️ Días 1–2: Encontrar y contener
- 1. Corré el triaje de arriba en cada repo, caché de CI, imagen de contenedor y laptop de desarrollo. Incluí Dockerfiles y SBOMs: los paquetes pueden llegar por una capa de imagen.
- 2. Fijá o quitá: npm a 0.1.20, PyPI a 2.0.33. Las marcas de tiempo de los registros las ubican el 3 de agosto y el 3 de septiembre, antes del incidente. No adoptaría la 0.1.22 ni la 0.1.24: SafeDep las llama limpias, pero no traen gitHead ni procedencia.
- 3. Tratá como comprometido todo host que cargó una versión afectada: matá sckit, borrá los dos directorios de caché de runtime, bloqueá skyleen[.]fr y buscá en logs de DNS y proxy desde el 23 de septiembre.
📅 Días 3–4: Rotar y auditar
- Tokens de registros: revocá y reemití tokens de npm (npmjs.com, Access Tokens), tokens de API de PyPI (Account settings, API tokens) y tokens de Hugging Face (Settings, Access Tokens). Hacelo desde una máquina limpia.
- Todo lo alcanzable desde $HOME: tokens de GitHub y GitLab, claves SSH, ~/.aws, ~/.git-credentials, .netrc, cachés de CLIs de nube, Vault y archivos .env en cualquier host expuesto.
- Prompts: listá qué se pegó en sesiones de agentes mientras el plugin estaba cargado (claves, datos de clientes) y decidí a quién hay que avisar.
- Lo que no hiciste vos: releases en npm, PyPI o Hugging Face que no hiciste, y un workflow runtime-update.yml o un directorio .sckit/ en cualquier repo que esos tokens alcancen.
📆 Día 5: Endurecer el camino de release y la entrada
- Trusted publishing y procedencia: publicá desde CI con PyPI Trusted Publishers y el trusted publishing de npm (OIDC) más provenance: sin token de larga vida que robar, y cada artefacto se traza a un build real.
- Cerrá la puerta del workflow: trusted publishing no sirve si cualquiera que pueda pushear un tag puede disparar el release. Protegé los tags de release, exigí revisores en el environment de release y revisá todo paso que escriba en $GITHUB_ENV; SafeDep reporta que así corrió un script antes del paso de publicación.
- Fijá y demorá: lockfiles con hashes (npm ci, pip install --require-hashes), nada de latest en plugins de agentes y un período de enfriamiento en las actualizaciones de dependencias. Todo el episodio cabe en un día de marcas de tiempo.
4. Qué Está Confirmado y Qué No (Revisado el 14 de Octubre de 2026)
‘Confirmado’ significa al menos dos registros independientes: un registro, OSV o GitHub más un informe de un proveedor, o dos proveedores con análisis propio. Todo lo demás va redactado como ‘según’.
Versiones afectadas
npm @memtensor/memos-cloud-openclaw-plugin 0.1.21, 0.1.23, 0.1.25 y PyPI MemoryOS 2.0.34. Coinciden Semgrep, SafeDep, Socket, CSA, OSV (MAL-2026-16475 y MAL-2026-16476) y GHSA-mhjf-v53x-7p87. Las versiones seguras, 0.1.20 y 2.0.33, las nombran Semgrep, SafeDep, Socket y CSA y las marcas de tiempo de los registros las fechan antes del incidente.
Estado de los registros hoy
npm: las tres versiones ya no están en la lista de versiones del paquete (siguen en su mapa de tiempos), latest apunta a 0.1.24, última modificación 23 sep 11:53 UTC. PyPI: el JSON lista 2.0.33 como última, sin 2.0.34 y sin nada yanked. CSA reporta que PyPI puso en cuarentena el release.
Tokens de Hugging Face
Según Semgrep, Socket y Aikido son un objetivo. El registro de OSV nombra archivos de credenciales de registros, Git, SSH y nube, y no menciona Hugging Face. Rotalos igual.
Autopropagación
OSV, SafeDep y Aikido describen código para reutilizar tokens robados y escribir un workflow en repos alcanzables. Semgrep y CSA (citando a StepSecurity) dicen que no hay evidencia de que se haya propagado. Una capacidad, no un brote confirmado.
Quién y cómo
Se desconoce. Ninguna fuente nombra a un actor; Aikido lo rastrea como supplychain.local, que es una etiqueta, no una atribución. SafeDep y Socket no pudieron confirmar cómo se obtuvo el acceso de push.
Comunicado de los mantenedores
No encontré ninguno. El 14 oct el repo de MemOS no muestra advisory de seguridad publicado, ningún commit en main después del 22 sep y un release v2.0.34 que sigue marcado Latest con una sola línea de descripción. Leí GitHub con una herramienta de fetch, así que verificalo vos.
Lo que no pude confirmar
No analicé los binarios ni los paquetes yo mismo: cada comportamiento descrito acá es lo que reportan Semgrep, SafeDep, Socket, Aikido, CSA y los registros de OSV. No pude confirmar quién publicó las 0.1.22 y 0.1.24 etiquetadas como limpias (SafeDep marca lo mismo), cuántas víctimas hay, ni si algún paquete downstream fue republicado con tokens robados. No encontré evidencia en ningún sentido.
Regla de oro
Tratá el plugin de memoria de un agente como parte de tu perímetro de credenciales: fijalo, demorá sus actualizaciones y publicalo solo desde un pipeline que un tag sin revisar no pueda disparar.
Conclusión
El compromiso de MemTensor es un ejemplo limpio de hacia dónde van los ataques a la cadena de suministro: no un hook de instalación, sino nombres de paquete reales desde un camino de release secuestrado, ejecutándose cuando tu agente arranca o recuerda algo, justo al lado de tus prompts y tokens. Las versiones afectadas ya no están en los registros; la exposición es una propiedad de las máquinas que alguna vez las cargaron.
Hacé el pase de cinco días: encontrar, rotar y después endurecer el pipeline desde el que publicás. Si mantenés paquetes, los puntos del día 5 son los que no postergaría: el token de la próxima víctima podría ser el tuyo.
Esta semana en una pantalla
Encontrar
- • Grep en lockfiles y SBOMs
- • Fijar 0.1.20 y 2.0.33
- • Revisar sckit y cachés
Rotar
- • Tokens npm, PyPI, Hugging Face
- • Claves Git, SSH y nube
- • Revisar prompts y releases
Endurecer
- • Trusted publishing + procedencia
- • Tags protegidos, revisores
- • Hashes en lockfile, enfriamiento
Fuentes
- Semgrep — The AI Ecosystem Has Worms Now: Inside the MemTensor Compromise
- OSV — MAL-2026-16475 (MemoryOS en PyPI)
- GitHub Advisory Database — GHSA-mhjf-v53x-7p87 (malware en el plugin npm)
- SafeDep — paquetes npm y PyPI de MemTensor golpeados por un gusano en Go
- Socket — compromiso de MemTensor
- Aikido — malware supplychain.local en npm y PyPI de MemTensor
- Cloud Security Alliance — AI Memory, Compromised: el ataque a la cadena de suministro de MemTensor
- Registro npm — metadatos de @memtensor/memos-cloud-openclaw-plugin (revisado el 14 oct 2026)
- PyPI — metadatos JSON de MemoryOS (revisado el 14 oct 2026)
- GitHub — releases de MemTensor/MemOS
- GitHub Advisory Database — GHSA-v9vw-ccqp-q298 (advisory de autenticación de MemOS, sin relación)



