MAL-2026-16475
Vulnerability from ossf_malicious_packages
Published
2026-09-23 00:00
Modified
2026-09-23 22:48
Summary
Malicious code in memoryos (PyPI)
Details

On September 23, 2026, an attacker published malicious versions of two MemTensor packages. The affected packages are the OpenClaw plugin @memtensor/memos-cloud-openclaw-plugin on npm and the MemOS Python library MemoryOS on PyPI. Both versions contain the same Go implant, sckit. The binary runs in the background each time the package loads. It collects credentials from the home directory and sends them to servers under skyleen[.]fr. It also includes the code it needs to copy itself into other repositories and packages that the stolen credentials can reach.

Credential collection: the implant's credentialPaths, readCredentialFile and extractJSONCredentials functions target .npmrc, .pypirc, .git-credentials, .netrc, id_rsa, id_ecdsa, id_ed25519, .vault-token, msal_token_cache, access_tokens.json and access_tokens.db. Two regular expressions pick out secrets: one matches secret-like variable names (token, secret, password, api_key, database_url), the other matches known token formats.

C2 protocol: the internal/wire package uses CBOR, X25519 key exchange and XChaCha20-Poly1305 (sckit/xchacha/v1), and handles signed leases, manifests and modules. The server delivers the modules at run time, so their contents were not observed. scheduleSelfDelete and deleteExecutable remove the binary after it runs.

C2 paths: /<24 hex>/config (control), /status (preflight), /batch (results).

Package archive SHA-256 digests: - memoryos-2.0.34-py3-none-any.whl: 39ee644406829a4b630b31759c20478bc22d576d6a59b253ed86f72c360aa5ef - memoryos-2.0.34.tar.gz: 92b46d18fc553c494eda714f204459edb74c205bf53b18a9092bcf02c7a6c5be


-= Per source details. Do not edit below this line.=-

Source: amazon-inspector (91081756ee0d7e550180abd300ce4ed9634862248dd07ea9eed5fb740e4aaffc)

On import memos, memos/init.py invokes configure_logging() which reaches memos._stage0.trigger(). That function locates a per-OS/arch prebuilt Go binary shipped inside the wheel at src/memos/.sckit/{darwin,linux,windows}-{amd64,arm64}/sckit (linux-amd64 is a 7.4MB ELF, sha256 c1b0998347b489582bae7b7f4930f9831d9ef4b6bc150cfd488ee1a43272dd36) and Popen-launches it detached (start_new_session=True, output silenced) with a base64 --config64 payload. The decoded configuration declares campaign_id "memos-semi-nuclear", an Ed25519 root_public key, state_dir $HOME/.memos/.cache/runtime, inventory_roots=["$HOME"], and three anonymous hex-subdomain fronts https://c747d139e7e9.skyleen.fr, https://73376a079d87.skyleen.fr and https://d4f77a3a8cb0.skyleen.fr with config/status/batch endpoints — instructing the launched agent to enumerate the installer's home directory and POST batches to attacker-controlled infrastructure. Separately, the package's PEP 517 build backend (sckit_poetry_build.py) wraps poetry.core.masonry and, when GITHUB_ENV is set, appends BASH_ENV=src/memos/_pypi_bridge.sh to $GITHUB_ENV so that any subsequent bash step in the same CI job auto-sources _pypi_bridge.sh; under a twine publish path this invokes _initial_ci_delivery.py to fetch and execute an Ed25519-signed emitter from https://10729e014d0e.skyleen.fr and reads $INPUT_PASSWORD and $PYPI_API_TOKEN before unsetting them, giving the attacker access to downstream publishing credentials. The combination of import-time detached execution of a bundled multi-arch binary, base64-obfuscated runtime manifest, anonymous hex-subdomain C2 fronts, declared $HOME inventory harvest, and a CI-only sideloader that steals publish tokens is a supply-chain implant.

Source: kam193 (d17530b4f32046961be6354a73139dafa5a7d73ca9f7226dcf6bb3a3510bde20)

Versions 2.0.34 were compromised.

The package was compromised and contains a malicious executable. First discovered by Safedep.


Category: MALICIOUS - The campaign has clearly malicious intent, like infostealers.

Campaign: 2026-09-compr-memoryos

Reasons (based on the campaign):

  • compromised-package
CWE
  • CWE-506 - The product contains code that appears to be malicious in nature.
  • CWE-506 - The product contains code that appears to be malicious in nature.

{
  "affected": [
    {
      "database_specific": {
        "cwes": [
          {
            "cweId": "CWE-506",
            "description": "The product contains code that appears to be malicious in nature.",
            "name": "Embedded Malicious Code"
          },
          {
            "cweId": "CWE-506",
            "description": "The product contains code that appears to be malicious in nature.",
            "name": "Embedded Malicious Code"
          }
        ],
        "indicators": {
          "evidence_files": [
            {
              "path": "src/memos/_stage0.py",
              "sha256": "881ea19936b0275f0d77c9d1a669b29595f7e274fef7bb7d82ec1690f8dbc591",
              "tlsh": "ad41e699cb283f8ca146423152117b6883a7c4437b0754ad34dc4dc8179b4aba0e48ff"
            },
            {
              "path": "sckit_poetry_build.py",
              "sha256": "497be589f382b321fa08d5583e7c7ff76daca18f988607a0051f8797b046ed86",
              "tlsh": "5621b734d21426a6a2f101e53922532182f7a06f4e426d28fd8cdd881f4e42a02f247d"
            }
          ],
          "package_integrity": [
            {
              "filename": "memoryos-2.0.34-py3-none-any.whl",
              "hashes": {
                "blake2b_256": "166972a6cc7f2a7a6ce286631bb176fb575dfd2378c2b74058a3e9b4cd0f1df9",
                "md5": "3d8db89d9fc419780fa557b5bbb6dd53",
                "sha256": "39ee644406829a4b630b31759c20478bc22d576d6a59b253ed86f72c360aa5ef"
              }
            },
            {
              "filename": "memoryos-2.0.34.tar.gz",
              "hashes": {
                "blake2b_256": "3e9a4d766a52dcabcbf440aa8f8f1eaf2adca041f93913271d8c342c20ae167c",
                "md5": "ecac3e301bc0b287fb4f5740a2cd8b8f",
                "sha256": "92b46d18fc553c494eda714f204459edb74c205bf53b18a9092bcf02c7a6c5be"
              }
            }
          ]
        }
      },
      "package": {
        "ecosystem": "PyPI",
        "name": "memoryos"
      },
      "versions": [
        "2.0.34"
      ]
    }
  ],
  "credits": [
    {
      "contact": [
        "inspector-research@amazon.com"
      ],
      "name": "Amazon Inspector",
      "type": "FINDER"
    },
    {
      "contact": [
        "https://github.com/kam193",
        "https://bad-packages.kam193.eu/"
      ],
      "name": "Kamil Ma\u0144kowski (kam193)",
      "type": "REPORTER"
    },
    {
      "contact": [
        "https://github.com/kam193",
        "https://bad-packages.kam193.eu/"
      ],
      "name": "Kamil Ma\u0144kowski (kam193)",
      "type": "ANALYST"
    },
    {
      "contact": [
        "https://safedep.io"
      ],
      "name": "SafeDep",
      "type": "FINDER"
    }
  ],
  "database_specific": {
    "iocs": {
      "domains": [
        "c747d139e7e9.skyleen.fr",
        "73376a079d87.skyleen.fr",
        "d4f77a3a8cb0.skyleen.fr"
      ],
      "files": [
        {
          "note": "Stage-0 loader shipped in the package.",
          "paths": [
            "memos/_stage0.py"
          ],
          "source": "PACKAGE_ARCHIVE"
        },
        {
          "digests": {
            "sha256": "c1b0998347b489582bae7b7f4930f9831d9ef4b6bc150cfd488ee1a43272dd36"
          },
          "note": "sckit Go implant, linux-amd64 build.",
          "source": "PACKAGE_ARCHIVE"
        },
        {
          "digests": {
            "sha256": "8f647f17a1934679c4095e21bee2b9bd83e28476603758bc91408a0c8443e3b4"
          },
          "note": "sckit Go implant, linux-arm64 build.",
          "source": "PACKAGE_ARCHIVE"
        },
        {
          "digests": {
            "sha256": "9de0d5b0ca184f71f630be5781d134998883a02d5d7bc65aeb9559d8f9efb364"
          },
          "note": "sckit Go implant, darwin-amd64 build.",
          "source": "PACKAGE_ARCHIVE"
        },
        {
          "digests": {
            "sha256": "5405e330507602e803f7dd6f2a9d4555aec8558ab222b51413594a962da6888a"
          },
          "note": "sckit Go implant, darwin-arm64 build.",
          "source": "PACKAGE_ARCHIVE"
        },
        {
          "digests": {
            "sha256": "16de381deb978744535b10f68fe15165251374b86eef18ffc2c47f61ea673047"
          },
          "note": "sckit Go implant, windows-amd64 build.",
          "source": "PACKAGE_ARCHIVE"
        },
        {
          "digests": {
            "sha256": "f7c4014e284f3d56c452b8b222a287c54f73dc4a40a7e022e765ac8376362947"
          },
          "note": "sckit Go implant, windows-arm64 build.",
          "source": "PACKAGE_ARCHIVE"
        },
        {
          "note": "Implant state directory.",
          "paths": [
            "$HOME/.memos/.cache/runtime"
          ],
          "source": "DROPPED"
        },
        {
          "note": "GitHub Actions workflow written by the worm for persistence; runs \u0027sckit stage0\u0027.",
          "paths": [
            "runtime-update.yml"
          ],
          "source": "DROPPED"
        },
        {
          "note": "CI tampering scripts; the implant also writes BASH_ENV= to $GITHUB_ENV.",
          "paths": [
            "sckit_poetry_build.py",
            "_pypi_bridge.sh",
            "sckit-publish-bridge.sh"
          ],
          "source": "DROPPED"
        }
      ],
      "urls": [
        "https://10729e014d0e.skyleen.fr/eb57efaa7365698fc1e4decc/initial-ci-v2"
      ]
    },
    "malicious-packages-origins": [
      {
        "id": "pypi/2026-09-compr-memoryos/memoryos",
        "import_time": "2026-09-23T11:39:55.779888783Z",
        "modified_time": "2026-09-23T11:05:40Z",
        "sha256": "d17530b4f32046961be6354a73139dafa5a7d73ca9f7226dcf6bb3a3510bde20",
        "source": "kam193",
        "versions": [
          "2.0.34"
        ]
      },
      {
        "id": "pypi/2026-09-compr-memoryos/memoryos",
        "import_time": "2026-09-23T12:27:29.81554581Z",
        "modified_time": "2026-09-23T11:24:20.192213Z",
        "sha256": "f615efcaee7120884365656085be5fdd17450a486945e6154004e36ddab0ac89",
        "source": "kam193",
        "versions": [
          "2.0.34"
        ]
      },
      {
        "id": "IN-MAL-2026-020490",
        "import_time": "2026-09-23T14:19:31.842786769Z",
        "modified_time": "2026-09-23T14:10:14Z",
        "sha256": "91081756ee0d7e550180abd300ce4ed9634862248dd07ea9eed5fb740e4aaffc",
        "source": "amazon-inspector",
        "versions": [
          "2.0.34"
        ]
      },
      {
        "id": "pypi/2026-09-compr-memoryos/memoryos",
        "import_time": "2026-09-23T19:16:13.107645438Z",
        "modified_time": "2026-09-23T11:24:20.192213Z",
        "sha256": "86a27870b919aa000ef05a66cedd4622cbf521a2ea6867a579dbec8c90d66f77",
        "source": "kam193",
        "versions": [
          "2.0.34"
        ]
      }
    ]
  },
  "details": "On September 23, 2026, an attacker published malicious versions of two MemTensor packages. The affected packages are the OpenClaw plugin @memtensor/memos-cloud-openclaw-plugin on npm and the MemOS Python library MemoryOS on PyPI. Both versions contain the same Go implant, sckit. The binary runs in the background each time the package loads. It collects credentials from the home directory and sends them to servers under skyleen[.]fr. It also includes the code it needs to copy itself into other repositories and packages that the stolen credentials can reach.\n\nCredential collection: the implant\u0027s `credentialPaths`, `readCredentialFile` and `extractJSONCredentials` functions target `.npmrc`, `.pypirc`, `.git-credentials`, `.netrc`, `id_rsa`, `id_ecdsa`, `id_ed25519`, `.vault-token`, `msal_token_cache`, `access_tokens.json` and `access_tokens.db`. Two regular expressions pick out secrets: one matches secret-like variable names (`token`, `secret`, `password`, `api_key`, `database_url`), the other matches known token formats.\n\nC2 protocol: the `internal/wire` package uses CBOR, X25519 key exchange and XChaCha20-Poly1305 (`sckit/xchacha/v1`), and handles signed leases, manifests and modules. The server delivers the modules at run time, so their contents were not observed. `scheduleSelfDelete` and `deleteExecutable` remove the binary after it runs.\n\nC2 paths: `/\u003c24 hex\u003e/config` (control), `/status` (preflight), `/batch` (results).\n\nPackage archive SHA-256 digests:\n- memoryos-2.0.34-py3-none-any.whl: 39ee644406829a4b630b31759c20478bc22d576d6a59b253ed86f72c360aa5ef\n- memoryos-2.0.34.tar.gz: 92b46d18fc553c494eda714f204459edb74c205bf53b18a9092bcf02c7a6c5be\n\n---\n_-= Per source details. Do not edit below this line.=-_\n\n## Source: amazon-inspector (91081756ee0d7e550180abd300ce4ed9634862248dd07ea9eed5fb740e4aaffc)\nOn `import memos`, memos/__init__.py invokes configure_logging() which reaches memos._stage0.trigger(). That function locates a per-OS/arch prebuilt Go binary shipped inside the wheel at src/memos/.sckit/{darwin,linux,windows}-{amd64,arm64}/sckit (linux-amd64 is a 7.4MB ELF, sha256 c1b0998347b489582bae7b7f4930f9831d9ef4b6bc150cfd488ee1a43272dd36) and Popen-launches it detached (start_new_session=True, output silenced) with a base64 --config64 payload. The decoded configuration declares campaign_id \"memos-semi-nuclear\", an Ed25519 root_public key, state_dir $HOME/.memos/.cache/runtime, inventory_roots=[\"$HOME\"], and three anonymous hex-subdomain fronts https://c747d139e7e9.skyleen.fr, https://73376a079d87.skyleen.fr and https://d4f77a3a8cb0.skyleen.fr with config/status/batch endpoints \u2014 instructing the launched agent to enumerate the installer\u0027s home directory and POST batches to attacker-controlled infrastructure. Separately, the package\u0027s PEP 517 build backend (sckit_poetry_build.py) wraps poetry.core.masonry and, when GITHUB_ENV is set, appends BASH_ENV=src/memos/_pypi_bridge.sh to $GITHUB_ENV so that any subsequent bash step in the same CI job auto-sources _pypi_bridge.sh; under a twine publish path this invokes _initial_ci_delivery.py to fetch and execute an Ed25519-signed emitter from https://10729e014d0e.skyleen.fr and reads $INPUT_PASSWORD and $PYPI_API_TOKEN before unsetting them, giving the attacker access to downstream publishing credentials. The combination of import-time detached execution of a bundled multi-arch binary, base64-obfuscated runtime manifest, anonymous hex-subdomain C2 fronts, declared $HOME inventory harvest, and a CI-only sideloader that steals publish tokens is a supply-chain implant.\n\n## Source: kam193 (d17530b4f32046961be6354a73139dafa5a7d73ca9f7226dcf6bb3a3510bde20)\nVersions 2.0.34 were compromised.\n\n\nThe package was compromised and contains a malicious executable. First discovered by Safedep.\n\n\n---\n\nCategory: MALICIOUS - The campaign has clearly malicious intent, like infostealers.\n\n\nCampaign: 2026-09-compr-memoryos\n\n\nReasons (based on the campaign):\n\n\n - compromised-package\n",
  "id": "MAL-2026-16475",
  "modified": "2026-09-23T22:48:18.185028831Z",
  "published": "2026-09-23T00:00:00Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://safedep.io/memtensor-sckit-worm-npm-pypi/"
    },
    {
      "type": "EVIDENCE",
      "url": "https://www.virustotal.com/gui/file/8f647f17a1934679c4095e21bee2b9bd83e28476603758bc91408a0c8443e3b4/detection"
    },
    {
      "type": "WEB",
      "url": "https://bad-packages.kam193.eu/pypi/campaign/2026-09-compr-memoryos"
    },
    {
      "type": "PACKAGE",
      "url": "https://pypi.org/project/MemoryOS/2.0.34/"
    },
    {
      "type": "REPORT",
      "url": "https://safedep.io/memtensor-sckit-worm-npm-pypi/"
    }
  ],
  "schema_version": "1.7.4",
  "summary": "Malicious code in memoryos (PyPI)"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…