AI DevelopmentSecurity

The MemOS and MemoryOS Supply-Chain Compromise: What to Check and Rotate

October 14, 2026
10 min read
Rows of small padlocked metal drawers in a dim archive, one slightly open
Share:

On 23 September 2026 an attacker published credential-stealing builds of two MemTensor packages: the npm OpenClaw plugin @memtensor/memos-cloud-openclaw-plugin (0.1.21, 0.1.23 and 0.1.25) and the PyPI library MemoryOS (2.0.34). According to the OSV malware records and several security vendors, the payload runs when the package is loaded, not at install, and hunts for npm, PyPI, Git, cloud and Hugging Face credentials.

Three weeks later the malicious versions are gone from registry metadata, but exposure belongs to every machine that ever loaded one. Here is what more than one source confirms, what rests on a single vendor, and the week of work I would run.

1. Context: What Happened on 23 September 2026

MemOS is described on GitHub as a memory operating system for LLMs and AI agents; MemoryOS is its PyPI package, and the npm plugin wires it into OpenClaw, an open-source personal AI assistant. This was not a typosquat: the names were real. According to the OSV record, an attacker with write access to the GitHub repository pushed malicious commits and a v2.0.34 tag, and the project’s own release workflow built and uploaded the PyPI file. On npm, SafeDep’s reconstruction shows five versions in about two hours, alternating malicious and clean.

Timeline, 23 September 2026 (UTC; SafeDep, registry metadata, OSV)

02:23 UTCnpm 0.1.21 published (malicious). The registry’s own timestamp matches SafeDep’s.
03:45–04:360.1.22 and 0.1.24 (clean, per SafeDep) alternate with 0.1.23 and 0.1.25 (malicious). Socket saw 0.1.25 holding latest; latest points to 0.1.24 today.
05:25 UTCPyPI MemoryOS 2.0.34 uploaded from the v2.0.34 tag (SafeDep).
23 SepOSV publishes PYSEC-2026-3987 and MAL-2026-16475 (PyPI) plus MAL-2026-16476 / GHSA-mhjf-v53x-7p87 (npm). Semgrep, SafeDep, Socket and Aikido publish the same day.
14 OctMy check: npm lists none of the three malicious versions and PyPI serves no 2.0.34, but GitHub still marks the v2.0.34 release as Latest.

No CVE for the compromise, but there is an advisory trail

None of the OSV records carries a CVE alias. The npm plugin has a GitHub malware advisory (GHSA-mhjf-v53x-7p87: affected 0.1.21, 0.1.23, 0.1.25; no patched version) and the PyPI file is covered by PYSEC-2026-3987 and MAL-2026-16475. Do not confuse this with CVE-2026-75110 / GHSA-v9vw-ccqp-q298, an unrelated August authentication advisory for MemOS that GitHub lists as unreviewed.

Practical consequence: the question is not ‘is my version vulnerable’ but ‘did anything on this machine ever load one of these four builds’. Semgrep says to treat any host that loaded an affected npm version or imported the PyPI one as compromised, even CI runners that only ran tests.

2. Four Implications for Teams Running AI Memory and Agent Plugins

These are the four consequences that change how I would treat agent dependencies, ordered by how often they will matter in a normal week.

🚪

Nothing runs at install, so install hardening does not help

Import and startup · SafeDep, Semgrep, OSV

Neither package uses an install hook. The Python side starts when the library sets up logging on import; the npm side starts when the OpenClaw gateway loads the plugin and again on every memory recall. --ignore-scripts and install-script allow-lists remain good practice, but they would not have stopped this.

🧠

A memory layer sits next to your prompts and your secrets

Recall hook · Semgrep, Socket, CSA

On npm, the recall hook passes the prompt text to the binary through an environment variable (SCKIT_EVENT_TEXT). Anything typed into the agent while an affected build was loaded, pasted keys included, should be treated as exposed. That is a data question as well as a token-rotation one.

🏭

The release path was the way in

Workflow and tags · OSV, SafeDep, Semgrep

PyPI’s 2.0.34 was built by the project’s own workflow from a tag on commits that were never on main. The npm builds came from the account that published 0.1.20 but carry no gitHead and no matching tag. SafeDep calls a stolen account token the most likely explanation and could not confirm it.

🪱

Worm-like design: your stolen token becomes someone else’s incident

Propagation · OSV, Aikido, Semgrep

OSV and Aikido describe code that reuses stolen publish tokens and writes a workflow into reachable repositories. Semgrep says it has no evidence this malware spread, and Aikido found no compromised public repos when it wrote. Treat it as a capability, and rotate so it never becomes a fact.

Read-only triage: find the packages and what they leave behind

Everything below only reads files and lists processes; none of it runs the packages. The indicators (state directories, process name and domain) come from the OSV records and SafeDep, not from my own analysis.

# 1. Lockfiles, manifests and SBOMs in every repo and CI cache
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. What is installed right now
npm ls --all 2>/dev/null | grep -i memos-cloud-openclaw-plugin
pip show MemoryOS 2>/dev/null | grep -i '^version'

# 3. Host artifacts named by the reports
ls -la ~/.openclaw/.cache/runtime ~/.memos/.cache/runtime 2>/dev/null
pgrep -fl sckit
# PowerShell: Get-Process sckit -ErrorAction SilentlyContinue

# 4. DNS, proxy and egress logs back to 23 Sep: skyleen.fr and subdomains
grep -rniE 'skyleen\.fr' /var/log 2>/dev/null

Removal is not cleanup

GitHub’s malware advisory says that removing the package may not remove what it left behind, and recommends rotating secrets from a different computer. Semgrep and Socket add: kill any sckit process and delete the runtime cache directories. If a host held publishing tokens, I would rebuild it from a clean image rather than clean it in place.

3. What to Do This Week

Five working days. Days 1–2 tell you whether you were exposed; days 3–4 assume you were; day 5 makes the next one harder.

☀️ Days 1–2: Find and contain

  1. 1. Run the triage above on every repo, CI cache, container image and developer laptop. Include Dockerfiles and SBOMs: the packages can arrive through an image layer.
  2. 2. Pin or remove: npm to 0.1.20, PyPI to 2.0.33. Registry timestamps place them on 3 Aug and 3 Sep, before the incident. I would not adopt 0.1.22 or 0.1.24: SafeDep calls them clean, but they carry no gitHead and no provenance.
  3. 3. Treat any host that loaded an affected build as compromised: kill sckit, delete the two runtime cache directories, block skyleen[.]fr and search DNS and proxy logs back to 23 September.

📅 Days 3–4: Rotate and audit

  1. Registry tokens: revoke and reissue npm tokens (npmjs.com, Access Tokens), PyPI API tokens (Account settings, API tokens) and Hugging Face tokens (Settings, Access Tokens). Do it from a clean machine.
  2. Everything reachable from $HOME: GitHub and GitLab tokens, SSH keys, ~/.aws, ~/.git-credentials, .netrc, cloud CLI caches, Vault and .env files on any exposed host.
  3. Prompts: list what was pasted into agent sessions while the plugin was loaded (keys, customer data) and decide who has to be told.
  4. What you did not do: releases on npm, PyPI or Hugging Face you did not make, and a runtime-update.yml workflow or a .sckit/ directory in any repo those tokens could reach.

📆 Day 5: Harden the release path and the intake

  1. Trusted publishing and provenance: publish from CI with PyPI Trusted Publishers and npm trusted publishing (OIDC) plus provenance: no long-lived token to steal, and every artifact traces to a real build.
  2. Close the workflow door: trusted publishing does not help if anyone who can push a tag can trigger the release. Protect release tags, require reviewers on the release environment, and review any step that writes to $GITHUB_ENV; SafeDep reports that is how a script ran before the publish step.
  3. Pin and delay: lockfiles with hashes (npm ci, pip install --require-hashes), no latest in agent plugins, and a release-age cooldown on dependency updates. The whole episode fits in one day of timestamps.

4. What Is Confirmed and What Is Not (Checked 14 October 2026)

‘Confirmed’ means at least two independent records: a registry, OSV or GitHub record plus a vendor write-up, or two vendors with their own analysis. Everything else is worded ‘according to’.

🟢

Affected versions

npm @memtensor/memos-cloud-openclaw-plugin 0.1.21, 0.1.23, 0.1.25 and PyPI MemoryOS 2.0.34. Semgrep, SafeDep, Socket, CSA, OSV (MAL-2026-16475 and MAL-2026-16476) and GHSA-mhjf-v53x-7p87 agree. The safe pins, 0.1.20 and 2.0.33, are named by Semgrep, SafeDep, Socket and CSA and dated before the incident by registry timestamps.

🟢

Registry status today

npm: the three versions are gone from the package’s version list (still present in its time map), latest points to 0.1.24, last modified 23 Sep 11:53 UTC. PyPI: JSON metadata lists 2.0.33 as latest, no 2.0.34, nothing yanked. CSA reports PyPI quarantined the release.

🟡

Hugging Face tokens

According to Semgrep, Socket and Aikido they are targeted. OSV’s record names registry, Git, SSH and cloud credential files and does not mention Hugging Face. Rotate them anyway.

🟡

Self-propagation

OSV, SafeDep and Aikido describe code to reuse stolen tokens and write a workflow into reachable repos. Semgrep and CSA (citing StepSecurity) say there is no evidence it spread. A capability, not a confirmed outbreak.

🟡

Who and how

Unknown. No source names an actor; Aikido tracks it as supplychain.local, which is a label, not attribution. SafeDep and Socket could not confirm how push access was obtained.

⚪

Maintainer statement

I found none. On 14 Oct the MemOS repo shows no published security advisory, no commit on main after 22 Sep, and a v2.0.34 release still marked Latest with a one-line body. I read GitHub through a fetch tool, so check it yourself.

What I could not confirm

I have not analysed the binaries or the packages myself: every behaviour here is as reported by Semgrep, SafeDep, Socket, Aikido, CSA and the OSV records. I could not confirm who published the clean-labelled 0.1.22 and 0.1.24 (SafeDep makes the same point), how many victims there are, or whether any downstream package was republished with stolen tokens. I found no evidence either way.

Golden rule

Treat an agent’s memory plugin as part of your credential perimeter: pin it, delay its updates, and publish it only from a pipeline an unreviewed tag cannot trigger.

Conclusion

The MemTensor compromise is a clean example of where supply-chain attacks are heading: not an install hook, but real package names from a hijacked release path, executing when your agent starts or recalls a memory, right next to your prompts and tokens. The affected builds are gone from the registries; exposure is a property of the machines that ever loaded them.

Do the five-day pass: find, rotate, then harden the pipeline you publish from. If you maintain packages yourself, the day-5 items are the ones I would not postpone: the next victim’s token could be yours.

This week in one screen

Find

  • • Grep lockfiles and SBOMs
  • • Pin 0.1.20 and 2.0.33
  • • Check sckit and cache dirs

Rotate

  • • npm, PyPI, Hugging Face tokens
  • • Git, SSH and cloud keys
  • • Review prompts and releases

Harden

  • • Trusted publishing + provenance
  • • Protected tags, reviewers
  • • Lockfile hashes, cooldown

Sources

Diego Rodriguez

Diego Rodriguez

Senior Full-Stack & AI Engineer

Diego has 10+ years of experience building production-grade AI-powered applications, from LLM orchestration and RAG pipelines to ML-driven risk detection and algorithmic trading systems.

Learn more about Diego →