/
← Voltar ao feed

MemTensor npm and PyPI packages backdoored with self-propagating Go worm sckit after GitHub Actions release token theft

1 fonte(s) · 1 atualização(ões) · publicado 22/09/2026 21:00 · coletado há 2 dias

On September 23, 2026, an attacker published malicious versions of @memtensor/memos-cloud-openclaw-plugin (npm, versions 0.1.21, 0.1.23 and 0.1.25 per the article) and the MemoryOS Python library (PyPI, 2.0.34). Both carry the same Go implant, sckit, which harvests credentials from the home directory, exfiltrates them to servers under skyleen[.]fr, and contains code to copy itself into other repositories and packages reachable with the stolen credentials. The attacker obtained the publish tokens by pushing commits to MemTensor's GitHub Actions release pipelines that leaked the npm and PyPI tokens before publishing. SafeDep found the incident after an issue on the plugin repository reported versions that matched no commit. The initial push access as the Memtensor-AI account is unexplained; a stolen token is the likely cause but is unconfirmed.

Detalhes técnicos

  • npm token theft: commits on short-lived sc/release-* branches (e.g. 9b97ec6) modified validate-release-confirmation.mjs to write BASH_ENV into $GITHUB_ENV, so sckit-publish-bridge.sh ran before the real publish step. It passed NPM_TOKEN to the sckit binary via collectStageZero(), deleted itself and exited 1, so the run published nothing. The branch was pushed five times between 00:48 and 02:03 UTC and deleted after each push.
  • PyPI token theft: tag v2.0.34 initially pointed to unsigned commit b52958f (not on main), which added six sckit binaries and a malicious Poetry build backend (sckit_poetry_build). It used the same BASH_ENV trick to run _pypi_bridge.sh inside the pypa publish action and send INPUT_PASSWORD to a skyleen[.]fr endpoint through _initial_ci_delivery.py. About two hours later commit 41bf5c7 ("chore: allow native PyPI upload [skip ci]") removed the register() call, the tag was recreated and MemTensor's own workflow published the malicious package with the real token. SafeDep reads the deleted tag v2.0.34-capture-1 as a token-capture run.
  • Execution: no install hook is used, so --ignore-scripts does not help. The npm plugin launches the binary on OpenClaw gateway start and on each memory recall, sending the user prompt as SCKIT_EVENT_TEXT. MemoryOS launches it from configure_logging(). Version 0.1.25 bundles ca-roots.pem and sets SSL_CERT_FILE on hosts without a system certificate store. The wheel grew from 951 KB to 19 MB.
  • Implant: Go go1.27.1, module supplychain.local/campaign/cmd/implant. It collects .npmrc, .pypirc, .git-credentials, .netrc, SSH keys, .vault-token, MSAL caches and secret-like environment variables, and matches token formats for AWS, GitHub, GitLab, npm, PyPI, Hugging Face, Vault, Slack, Stripe and SendGrid. Worm functions (findRepositories, PrepareRemoteRepository, recursivePublish) write loaders into victim repos, including a runtime-update.yml GitHub Actions workflow. It has geo and TLS-fingerprint filtering fields (geo_iso, deny_iso, ja4_deny), a CBOR/X25519/XChaCha20-Poly1305 C2 protocol with signed modules, and self-delete routines. Campaign IDs are cloud-openclaw-semi-nuclear and memos-semi-nuclear; not_after decodes to roughly October 22-23, 2026.
  • The article suggests, as an unconfirmed inference, that a language model helped write the tooling. Affected-package lists may grow because the worm spreads.

Remediação

  • Remove the affected packages and pin clean versions: 0.1.20 for the plugin and 2.0.33 for MemoryOS.
  • Kill any sckit process and delete $HOME/.openclaw/.cache/runtime and $HOME/.memos/.cache/runtime.
  • Rotate every credential reachable from $HOME and the process environment (npm, PyPI, GitHub, GitLab, SSH, cloud CLI tokens, .env secrets).
  • Check repositories you can push to for an unexpected runtime-update.yml workflow or a .sckit/ directory.
  • Maintainers: do not let publish jobs trust scripts from the commit being built, use trusted publishing, protected tags, required reviewers on the release environment, and provenance attestations.

Linha do tempo

  1. safedep.io ↗ · pub. 22/09/2026 21:00 · coletado 19/10 18:03 primeiro registro

    MemTensor npm and PyPI packages backdoored with self-propagating Go worm sckit after GitHub Actions release token theft

    ler a análise desta fonte

    On September 23, 2026, an attacker published malicious versions of @memtensor/memos-cloud-openclaw-plugin (npm, versions 0.1.21, 0.1.23 and 0.1.25 per the article) and the MemoryOS Python library (PyPI, 2.0.34). Both carry the same Go implant, sckit, which harvests credentials from the home directory, exfiltrates them to servers under skyleen[.]fr, and contains code to copy itself into other repositories and packages reachable with the stolen credentials. The attacker obtained the publish tokens by pushing commits to MemTensor's GitHub Actions release pipelines that leaked the npm and PyPI tokens before publishing. SafeDep found the incident after an issue on the plugin repository reported versions that matched no commit. The initial push access as the Memtensor-AI account is unexplained; a stolen token is the likely cause but is unconfirmed.

    Technical Details

    • npm token theft: commits on short-lived sc/release-* branches (e.g. 9b97ec6) modified validate-release-confirmation.mjs to write BASH_ENV into $GITHUB_ENV, so sckit-publish-bridge.sh ran before the real publish step. It passed NPM_TOKEN to the sckit binary via collectStageZero(), deleted itself and exited 1, so the run published nothing. The branch was pushed five times between 00:48 and 02:03 UTC and deleted after each push.
    • PyPI token theft: tag v2.0.34 initially pointed to unsigned commit b52958f (not on main), which added six sckit binaries and a malicious Poetry build backend (sckit_poetry_build). It used the same BASH_ENV trick to run _pypi_bridge.sh inside the pypa publish action and send INPUT_PASSWORD to a skyleen[.]fr endpoint through _initial_ci_delivery.py. About two hours later commit 41bf5c7 ("chore: allow native PyPI upload [skip ci]") removed the register() call, the tag was recreated and MemTensor's own workflow published the malicious package with the real token. SafeDep reads the deleted tag v2.0.34-capture-1 as a token-capture run.
    • Execution: no install hook is used, so --ignore-scripts does not help. The npm plugin launches the binary on OpenClaw gateway start and on each memory recall, sending the user prompt as SCKIT_EVENT_TEXT. MemoryOS launches it from configure_logging(). Version 0.1.25 bundles ca-roots.pem and sets SSL_CERT_FILE on hosts without a system certificate store. The wheel grew from 951 KB to 19 MB.
    • Implant: Go go1.27.1, module supplychain.local/campaign/cmd/implant. It collects .npmrc, .pypirc, .git-credentials, .netrc, SSH keys, .vault-token, MSAL caches and secret-like environment variables, and matches token formats for AWS, GitHub, GitLab, npm, PyPI, Hugging Face, Vault, Slack, Stripe and SendGrid. Worm functions (findRepositories, PrepareRemoteRepository, recursivePublish) write loaders into victim repos, including a runtime-update.yml GitHub Actions workflow. It has geo and TLS-fingerprint filtering fields (geo_iso, deny_iso, ja4_deny), a CBOR/X25519/XChaCha20-Poly1305 C2 protocol with signed modules, and self-delete routines. Campaign IDs are cloud-openclaw-semi-nuclear and memos-semi-nuclear; not_after decodes to roughly October 22-23, 2026.
    • The article suggests, as an unconfirmed inference, that a language model helped write the tooling. Affected-package lists may grow because the worm spreads.

    Remediation

    • Remove the affected packages and pin clean versions: 0.1.20 for the plugin and 2.0.33 for MemoryOS.
    • Kill any sckit process and delete $HOME/.openclaw/.cache/runtime and $HOME/.memos/.cache/runtime.
    • Rotate every credential reachable from $HOME and the process environment (npm, PyPI, GitHub, GitLab, SSH, cloud CLI tokens, .env secrets).
    • Check repositories you can push to for an unexpected runtime-update.yml workflow or a .sckit/ directory.
    • Maintainers: do not let publish jobs trust scripts from the commit being built, use trusted publishing, protected tags, required reviewers on the release environment, and provenance attestations.