Desarrollo IASeguridad

El Compromiso de MemOS y MemoryOS: Qué Revisar y Qué Rotar

14 de octubre de 2026
10 min de lectura
Filas de cajones metálicos pequeños con candado en un archivo en penumbra, uno apenas abierto
Compartir:

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)

02:23 UTCSe publica npm 0.1.21 (maliciosa). La marca de tiempo del propio registro coincide con la de SafeDep.
03:45–04:360.1.22 y 0.1.24 (limpias, según SafeDep) se alternan con 0.1.23 y 0.1.25 (maliciosas). Socket vio la 0.1.25 con el tag latest; hoy latest apunta a 0.1.24.
05:25 UTCSe sube MemoryOS 2.0.34 a PyPI desde el tag v2.0.34 (SafeDep).
23 sepOSV publica PYSEC-2026-3987 y MAL-2026-16475 (PyPI) más MAL-2026-16476 / GHSA-mhjf-v53x-7p87 (npm). Semgrep, SafeDep, Socket y Aikido publican el mismo día.
14 octMi chequeo: npm no lista ninguna de las tres versiones maliciosas y PyPI no sirve 2.0.34, pero GitHub sigue marcando el release v2.0.34 como Latest.

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. 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. 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. 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

  1. 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.
  2. 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.
  3. 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.
  4. 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

  1. 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.
  2. 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.
  3. 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

Diego Rodriguez

Diego Rodriguez

Ingeniero Senior Full-Stack & AI

Diego tiene mas de 9 anos de experiencia construyendo aplicaciones potenciadas por IA de produccion, desde orquestacion de LLMs y pipelines RAG hasta deteccion de riesgos con ML y sistemas de trading algoritmico.

Conoce mas sobre Diego →