{
  "campaign": {
    "name": "wshu.net npm Credential-Stealer Campaign",
    "slug": "wshu-net-npm-credential-stealer-campaign",
    "href": "/ti/campaigns/wshu-net-npm-credential-stealer-campaign",
    "description": "ACTIVELY ONGOING single-actor npm supply chain campaign, named for the wshu.net publisher infrastructure that ties its members together; @apexcraft/nano-key is the convicted ROOT/lineage member (secondary identifier). Amazon Inspector security research (Chi Tran, 2026-06-19) independently documented the SAME cluster as 'Operation Friday Harvest' (same 13 wshu.net scopes, same <scope>-<6char>@wshu.net burner pattern, same ~260-282KB obfuscator.io payload, same dual-trigger) - independent corroboration that raises confidence on the cluster to HIGH/confirmed. Confirmed members now total 15 packages across 13 throwaway scopes seeded on 2026-06-04; THREE of those scopes (@zynkit, @frostnode, @gleamkit) each hold a payload-free scope-reservation probe stub. Amazon Inspector's fuller version enumeration shows 64 malicious versions across the cluster (broader ranges than SafeDep statically pulled - e.g. @apexcraft/nano-key 1.2.4/1.2.5/1.3.2-1.3.8, @glitchpad/throttler 2.1.1/2.2.1-2.2.4, @nullzero/urlcat 1.4.0-1.4.3, @tinyfox/shapecheck 0.7.4/0.8.5-0.8.8, @zynkit/jwtbytes 0.4.3/0.5.1-0.5.4). Each payload package masquerades as a small developer utility (JWT/byte helper, retry wrapper, shape validator, throttler, logger, hex parser, env validator, datetime lib, RxJS poll operator) but ships a 259-282KB javascript-obfuscator payload blob executed via a postinstall hook. CORRECTED PAYLOAD BEHAVIOR (Amazon Inspector dynamic analysis SUPERSEDES the earlier static hypothesis): the obfuscated JS blob is a DOWNLOADER/LOADER, not a self-contained browser-credential stealer. It spawns a detached child process behind env-var guards, downloads a ~10.6MB Rust-compiled binary from GitHub Releases (github.com/angelmaybeth21-oss/test/releases/download/v1.0.0/{linux,mac,win.js}), and executes it. The Rust binary is the actual infostealer: 30+ crypto wallets (MetaMask, Phantom, Trust Wallet, Solflare, Keplr, Ledger, Trezor, ...), browser credentials (Chrome/Brave/Firefox/Edge passwords/cookies/history/autofill/cards), cloud tokens (AWS/GCP/Azure/Kubernetes), SSH keys, Discord tokens + Telegram session data, developer creds (npm tokens/.env/.npmrc/GitHub PAT/PyPI tokens), and DB client connection strings (DBeaver/pgAdmin/MongoDB Compass). Persistence: a systemd USER service masquerading as a benign daemon (observed colord, haveged) at ~/.local/bin/<daemon> + ~/.config/systemd/user/<daemon>.service. Exfil C2: the Windows variant uses the Telegram Bot API (api.telegram.org, 149.154.166.110); Linux/macOS variants POST multipart/form-data over HTTP (minreq lib), gated behind anti-VM checks (Windows is NOT gated). The EARLIER static hypothesis - that the payload was itself the convicted @apexcraft/nano-key Chromium browser-credential stealer (Cookies/Login Data -> aes-256-gcm decrypt -> HTTPS exfil) - is now SUPERSEDED by this confirmed downloader->Rust-infostealer chain; browser-credential theft survives only as one capability of the Rust second stage, not the whole payload. SafeDep's independently-verified FIRST-STAGE observations stand: obfuscator.io RC4+base64 string decoder, the guarded runPrepare()/onInstall() wrapper auto-fired via require.main===module, dynamic require to keep module names out of the static graph, and byte-identical/near-identical compiled blobs. The STRONGER pivot is the GitHub delivery account angelmaybeth21-oss (created 2026-06-03; repo 'test' now removed but account live) and secondary smilingdusty233 (created 2026-05-31) - not the shared disposable wshu.net email. The DURABLE campaign fingerprint is the shared obfuscator.io template plus 5 build clusters (A-E) keyed by string-array function name and re-entrancy guard tag (A=_0xe119/__EE9863E13F_TAG: @apexcraft,@briskforge,@chunklab; B=_0x36b9/__7D0A53D40B_TAG: @glitchpad,@nullzero,@lazyutil; C=_0x175f/__38CC632841_TAG: @petitcode,@tinyfox,@thymelab,@zynkit; D=_0x5da4/__70FE9F7AB6_TAG: @bytemend; E=_0x15fd/__4C6BA78C7C_TAG: @frostnode) - members in the same cluster share the same obfuscator seed, which explains SafeDep's byte-identical-blob finding. CORRECTION: wshu.net is a PUBLIC DISPOSABLE-EMAIL provider (on disposable-email-domains, fakefilter, MISP warninglists, authgear's free-email list, and in unrelated apps' temp-mail signup logs), so the wshu.net domain ALONE is a NOISY pivot, NOT a unique attacker-owned indicator. Latest dist-tag of every payload package was republished with empty scripts to evade casual npm view metadata checks while the payload remains in mid-versions. @nullzero/urlcat (publisher nullzero-rlnozk@wshu.net) is a same-actor member whose flagged version 1.4.2 was UNPUBLISHED before SafeDep static inspection. The earlier noon-contracts npm package (2026-05-10, publisher noondeved94ed@wshu.net) shares ONLY the disposable-email provider, not payload or code; that link is WEAKENED - treat it as a low/medium-confidence lead.",
    "objective": "Compromise developer and CI hosts at scale: install-time obfuscated npm packages download and run a Rust-compiled infostealer that harvests crypto wallets, browser credentials, cloud/SSH/developer tokens, and chat-app sessions, exfiltrated via Telegram (Windows) or HTTP multipart (Linux/macOS).",
    "aliases": [
      "Operation Friday Harvest",
      "@apexcraft/nano-key lineage",
      "wshu.net stealer cluster"
    ],
    "discovered_at": "2026-06-23"
  },
  "packages": [
    {
      "ecosystem": "npm",
      "name": "@apexcraft/nano-key",
      "href": "/ti/packages/npm/@apexcraft/nano-key",
      "threat_types": [
        "credential_stealer",
        "data_exfiltration",
        "persistence",
        "crypto_drainer",
        "c2_agent",
        "typosquat",
        "other"
      ],
      "versions": [
        "1.2.4",
        "1.2.5",
        "1.3.2",
        "1.3.3",
        "1.3.4",
        "1.3.5",
        "1.3.6",
        "1.3.7",
        "1.3.8"
      ]
    },
    {
      "ecosystem": "npm",
      "name": "@bytemend/mfebus",
      "href": "/ti/packages/npm/@bytemend/mfebus",
      "threat_types": [
        "credential_stealer",
        "data_exfiltration",
        "persistence",
        "typosquat"
      ],
      "versions": [
        "1.4.2"
      ]
    },
    {
      "ecosystem": "npm",
      "name": "@chunklab/hexparse",
      "href": "/ti/packages/npm/@chunklab/hexparse",
      "threat_types": [
        "credential_stealer",
        "data_exfiltration",
        "persistence",
        "typosquat"
      ],
      "versions": [
        "1.0.7",
        "1.1.4",
        "1.1.5",
        "1.1.6"
      ]
    },
    {
      "ecosystem": "npm",
      "name": "@zynkit/jwtbytes",
      "href": "/ti/packages/npm/@zynkit/jwtbytes",
      "threat_types": [
        "credential_stealer",
        "data_exfiltration",
        "persistence",
        "typosquat"
      ],
      "versions": [
        "0.4.3",
        "0.5.1",
        "0.5.2",
        "0.5.3",
        "0.5.4"
      ]
    },
    {
      "ecosystem": "npm",
      "name": "@zynkit/probe",
      "href": "/ti/packages/npm/@zynkit/probe",
      "threat_types": [
        "other"
      ],
      "versions": [
        "0.0.1"
      ]
    },
    {
      "ecosystem": "npm",
      "name": "@petitcode/eb-retry",
      "href": "/ti/packages/npm/@petitcode/eb-retry",
      "threat_types": [
        "credential_stealer",
        "data_exfiltration",
        "persistence",
        "typosquat"
      ],
      "versions": [
        "1.3.5"
      ]
    },
    {
      "ecosystem": "npm",
      "name": "@tinyfox/shapecheck",
      "href": "/ti/packages/npm/@tinyfox/shapecheck",
      "threat_types": [
        "credential_stealer",
        "data_exfiltration",
        "persistence",
        "typosquat"
      ],
      "versions": [
        "0.7.4",
        "0.8.5",
        "0.8.6",
        "0.8.7",
        "0.8.8"
      ]
    },
    {
      "ecosystem": "npm",
      "name": "@glitchpad/throttler",
      "href": "/ti/packages/npm/@glitchpad/throttler",
      "threat_types": [
        "credential_stealer",
        "data_exfiltration",
        "persistence",
        "typosquat"
      ],
      "versions": [
        "2.1.1",
        "2.2.1",
        "2.2.2",
        "2.2.3",
        "2.2.4"
      ]
    },
    {
      "ecosystem": "npm",
      "name": "@thymelab/logfx",
      "href": "/ti/packages/npm/@thymelab/logfx",
      "threat_types": [
        "credential_stealer",
        "data_exfiltration",
        "persistence",
        "typosquat"
      ],
      "versions": [
        "2.15.5"
      ]
    },
    {
      "ecosystem": "npm",
      "name": "@briskforge/envcheck",
      "href": "/ti/packages/npm/@briskforge/envcheck",
      "threat_types": [
        "credential_stealer",
        "data_exfiltration",
        "persistence",
        "typosquat"
      ],
      "versions": [
        "0.5.2",
        "0.5.3",
        "0.5.4"
      ]
    },
    {
      "ecosystem": "npm",
      "name": "@lazyutil/dater",
      "href": "/ti/packages/npm/@lazyutil/dater",
      "threat_types": [
        "credential_stealer",
        "data_exfiltration",
        "persistence",
        "typosquat"
      ],
      "versions": [
        "0.8.1",
        "0.9.2",
        "0.9.3",
        "0.9.4"
      ]
    },
    {
      "ecosystem": "npm",
      "name": "@frostnode/waitfor",
      "href": "/ti/packages/npm/@frostnode/waitfor",
      "threat_types": [
        "credential_stealer",
        "data_exfiltration",
        "persistence",
        "typosquat"
      ],
      "versions": [
        "0.9.0",
        "0.10.3",
        "0.10.4",
        "0.10.5"
      ]
    },
    {
      "ecosystem": "npm",
      "name": "@nullzero/urlcat",
      "href": "/ti/packages/npm/@nullzero/urlcat",
      "threat_types": [
        "credential_stealer",
        "data_exfiltration",
        "persistence",
        "typosquat"
      ],
      "versions": [
        "1.4.0",
        "1.4.1",
        "1.4.2",
        "1.4.3"
      ]
    },
    {
      "ecosystem": "npm",
      "name": "@frostnode/probe",
      "href": "/ti/packages/npm/@frostnode/probe",
      "threat_types": [
        "other"
      ],
      "versions": [
        "0.0.1"
      ]
    },
    {
      "ecosystem": "npm",
      "name": "@gleamkit/probe",
      "href": "/ti/packages/npm/@gleamkit/probe",
      "threat_types": [
        "other"
      ],
      "versions": [
        "0.0.1"
      ]
    }
  ],
  "indicators": [
    {
      "kind": "domain",
      "value": "wshu.net",
      "href": "/ti/ioc/domain/wshu.net",
      "context": "SUPPORTING signal, NOT a unique attacker indicator. wshu.net is a PUBLIC DISPOSABLE-EMAIL provider (verified on disposable-email blocklists: disposable-email-domains, fakefilter, MISP warninglists, authgear free-email list, and in unrelated apps' temp-mail signup logs), so the domain alone catches many unrelated throwaway accounts and is a noisy pivot. The campaign uses the per-scope burner pattern <scope>-<6rand>@wshu.net across all 12 scopes; treat that pattern as corroborating evidence only when combined with the durable code fingerprint (shared runPrepare/onInstall javascript-obfuscator wrapper + byte-identical/near-identical payload blobs + the 2026-06-04 publish burst), not as a standalone domain pivot. The earlier noon-contracts npm package (publisher noondeved94ed@wshu.net, 2026-05-10) shares only this disposable-email provider, not payload or code."
    },
    {
      "kind": "file_path",
      "value": "require(_0x45af03['GyrZN'])",
      "href": "/ti/ioc/file_path/file_path-abc1dfe8aa1c",
      "context": "Dynamically-obscured require with an identical variable name (_0x45af03) and proxy key (GyrZN) across most campaign payload blobs. Resolves a Node built-in module name from a decrypted RC4 string at runtime to keep it out of the static module graph. Cross-package code fingerprint."
    },
    {
      "kind": "email",
      "value": "noondeved94ed@wshu.net",
      "href": "/ti/ioc/email/noondeved94ed@wshu.net",
      "context": "Email indicator from blog post"
    },
    {
      "kind": "github_repo",
      "value": "angelmaybeth21-oss/test",
      "href": "/ti/ioc/github_repo/github_repo-775c00203526",
      "context": "Second-stage delivery (Amazon Inspector / Operation Friday Harvest). The obfuscated first-stage downloader pulls a ~10.6MB Rust infostealer from this account's GitHub Releases. STRONGER pivot than the shared disposable wshu.net email. Account angelmaybeth21-oss created 2026-06-03; repo 'test' now removed but the account is still live. Dropper URL pattern: github.com/angelmaybeth21-oss/test/releases/download/v1.0.0/{linux,mac,win.js}. SafeDep independently verified the account exists via the GitHub API this session."
    },
    {
      "kind": "github_repo",
      "value": "smilingdusty233",
      "href": "/ti/ioc/github_repo/github_repo-abe30b873eb2",
      "context": "Secondary GitHub delivery/staging account associated with the campaign (Amazon Inspector). Created 2026-05-31. SafeDep independently verified the account exists via the GitHub API this session."
    },
    {
      "kind": "file_path",
      "value": "__[0-9A-F]{10}_TAG",
      "href": "/ti/ioc/file_path/file_path-27588d08861d",
      "context": "Re-entrancy guard variable-name pattern in the obfuscator.io first-stage blobs (e.g. __EE9863E13F_TAG). Together with the string-array function name it defines the 5 build clusters (A=__EE9863E13F_TAG, B=__7D0A53D40B_TAG, C=__38CC632841_TAG, D=__70FE9F7AB6_TAG, E=__4C6BA78C7C_TAG). Members in the same cluster share an obfuscator seed, explaining the byte-identical blob reuse (Amazon Inspector + SafeDep). Hunt as a code/regex fingerprint."
    },
    {
      "kind": "email",
      "value": "apexcraft-8uiljr@wshu.net",
      "href": "/ti/ioc/email/apexcraft-8uiljr@wshu.net",
      "context": "npm publisher email for the @apexcraft scope (root @apexcraft/nano-key)."
    },
    {
      "kind": "sha256",
      "value": "618dfffb6829356c131fded9f4c6528b73b4f9d7ff1fc1d3b457599a12584e29",
      "href": "/ti/ioc/sha256/618dfffb6829356c131fded9f4c6528b73b4f9d7ff1fc1d3b457599a12584e29",
      "context": "Obfuscated payload blob dist/cjs/seed.cjs in @apexcraft/nano-key 1.3.7 (277264 bytes)."
    },
    {
      "kind": "url",
      "value": "https://github.com/angelmaybeth21-oss/test/releases/download/v1.0.0/linux",
      "href": "/ti/ioc/url/url-b570e94c0373",
      "context": "GitHub Releases dropper URL for the Linux Rust infostealer ELF second stage (Amazon Inspector). Pattern: .../v1.0.0/{linux,mac,win.js}."
    },
    {
      "kind": "url",
      "value": "https://github.com/angelmaybeth21-oss/test/releases/download/v1.0.0/mac",
      "href": "/ti/ioc/url/url-3c45d689277a",
      "context": "GitHub Releases dropper URL for the macOS Rust infostealer Mach-O second stage (Amazon Inspector)."
    },
    {
      "kind": "url",
      "value": "https://github.com/angelmaybeth21-oss/test/releases/download/v1.0.0/win.js",
      "href": "/ti/ioc/url/url-cb8182ed6fb1",
      "context": "GitHub Releases dropper URL for the Windows Rust infostealer second stage (Amazon Inspector). The win.js name is a masquerade; the artifact is the Windows binary."
    },
    {
      "kind": "sha256",
      "value": "2457b2e775a5fe7a9e022ba77074a1b9aacb41b4fc0cc1d8a3dc66546599c5de",
      "href": "/ti/ioc/sha256/2457b2e775a5fe7a9e022ba77074a1b9aacb41b4fc0cc1d8a3dc66546599c5de",
      "context": "Second-stage Rust infostealer Linux ELF (~10.6MB) downloaded from github.com/angelmaybeth21-oss/test/releases/download/v1.0.0/linux. Attributed to Amazon Inspector dynamic analysis (VirusTotal/CAPE)."
    },
    {
      "kind": "sha256",
      "value": "b1c7b17f31a84e2596250121c3610ae5e0d592651940dd6c0dd74506f0f38313",
      "href": "/ti/ioc/sha256/b1c7b17f31a84e2596250121c3610ae5e0d592651940dd6c0dd74506f0f38313",
      "context": "Second-stage Rust infostealer macOS Mach-O downloaded from github.com/angelmaybeth21-oss/test/releases/download/v1.0.0/mac. Attributed to Amazon Inspector dynamic analysis."
    },
    {
      "kind": "sha256",
      "value": "11fe3a47333f63fd0e0a32ea16351eb302659aba983c07e4ea3dc9b09b618509",
      "href": "/ti/ioc/sha256/11fe3a47333f63fd0e0a32ea16351eb302659aba983c07e4ea3dc9b09b618509",
      "context": "Second-stage Rust infostealer Windows binary (win.js) downloaded from github.com/angelmaybeth21-oss/test/releases/download/v1.0.0/win.js. Windows variant exfils via Telegram Bot API and is NOT anti-VM gated. Attributed to Amazon Inspector dynamic analysis."
    },
    {
      "kind": "domain",
      "value": "api.telegram.org",
      "href": "/ti/ioc/domain/api.telegram.org",
      "context": "Telegram Bot API used as exfil C2 by the Windows variant of the Rust infostealer second stage (Amazon Inspector). Resolves to 149.154.166.110. Linux/macOS variants exfil over HTTP multipart/form-data instead."
    },
    {
      "kind": "ipv4",
      "value": "149.154.166.110",
      "href": "/ti/ioc/ipv4/149.154.166.110",
      "context": "Telegram infrastructure IP for api.telegram.org, the Windows-variant exfil C2 of the Rust infostealer second stage (Amazon Inspector)."
    },
    {
      "kind": "file_path",
      "value": "/tmp/_installer-0/",
      "href": "/ti/ioc/file_path/file_path-bd870497e0ed",
      "context": "Host staging directory created by the downloader/second stage (Amazon Inspector)."
    },
    {
      "kind": "file_path",
      "value": "~/.local/bin/<daemon>",
      "href": "/ti/ioc/file_path/file_path-c6d1a66f7f4e",
      "context": "Persistence binary path for the Rust infostealer, masquerading as a benign daemon (observed names: colord, haveged). Paired with the systemd user unit at ~/.config/systemd/user/<daemon>.service (Amazon Inspector)."
    },
    {
      "kind": "file_path",
      "value": "~/.config/systemd/user/<daemon>.service",
      "href": "/ti/ioc/file_path/file_path-f99665105320",
      "context": "systemd USER service unit installed for persistence, masquerading as a benign daemon (colord, haveged). Loads ~/.local/bin/<daemon> (Amazon Inspector)."
    },
    {
      "kind": "file_path",
      "value": "~/.local/state/<daemon>/{install.nonce,machine.id}",
      "href": "/ti/ioc/file_path/file_path-5c4a3842570c",
      "context": "Host state artifacts (install nonce + machine id) written by the Rust infostealer second stage (Amazon Inspector)."
    },
    {
      "kind": "email",
      "value": "bytemend-dwzfhq@wshu.net",
      "href": "/ti/ioc/email/bytemend-dwzfhq@wshu.net",
      "context": "npm publisher email for the @bytemend scope (@bytemend/mfebus)."
    },
    {
      "kind": "sha256",
      "value": "a9a28f2e9f7e0348092682940b3bf63d47a63afc18eb8bfe628e5ddab0d73b47",
      "href": "/ti/ioc/sha256/a9a28f2e9f7e0348092682940b3bf63d47a63afc18eb8bfe628e5ddab0d73b47",
      "context": "Obfuscated payload blob dist/bootstrap.js in @bytemend/mfebus 1.4.2 (277306 bytes)."
    },
    {
      "kind": "email",
      "value": "chunklab-bpriqx@wshu.net",
      "href": "/ti/ioc/email/chunklab-bpriqx@wshu.net",
      "context": "npm publisher email for the @chunklab scope (@chunklab/hexparse)."
    },
    {
      "kind": "sha256",
      "value": "24c8f9b8ac17c2f88cc01d44543963206472112510962b68cf5f74d598b3b065",
      "href": "/ti/ioc/sha256/24c8f9b8ac17c2f88cc01d44543963206472112510962b68cf5f74d598b3b065",
      "context": "Obfuscated payload blob script/prelude.cjs in @chunklab/hexparse 1.1.6 (277265 bytes)."
    },
    {
      "kind": "email",
      "value": "zynkit-sk393b@wshu.net",
      "href": "/ti/ioc/email/zynkit-sk393b@wshu.net",
      "context": "npm publisher email for the @zynkit scope (@zynkit/jwtbytes and the @zynkit/probe stub)."
    },
    {
      "kind": "sha256",
      "value": "d06ee17d30ebb333ab2e5b6e8a1324fcf95edaaae17b6793ec0f3647338efda1",
      "href": "/ti/ioc/sha256/d06ee17d30ebb333ab2e5b6e8a1324fcf95edaaae17b6793ec0f3647338efda1",
      "context": "Obfuscated payload blob dist/prelude.cjs in @zynkit/jwtbytes 0.5.3 (282050 bytes)."
    },
    {
      "kind": "email",
      "value": "petitcode-eq1efk@wshu.net",
      "href": "/ti/ioc/email/petitcode-eq1efk@wshu.net",
      "context": "npm publisher email for the @petitcode scope (@petitcode/eb-retry)."
    },
    {
      "kind": "sha256",
      "value": "32d02f806d58a6670f7cc9b93f1d85b22e0e0f535e1f90a62d86918033896f54",
      "href": "/ti/ioc/sha256/32d02f806d58a6670f7cc9b93f1d85b22e0e0f535e1f90a62d86918033896f54",
      "context": "Obfuscated payload blob lib/warmup.js in @petitcode/eb-retry 1.3.5 (282294 bytes)."
    },
    {
      "kind": "email",
      "value": "tinyfox-yjwiqz@wshu.net",
      "href": "/ti/ioc/email/tinyfox-yjwiqz@wshu.net",
      "context": "npm publisher email for the @tinyfox scope (@tinyfox/shapecheck)."
    },
    {
      "kind": "sha256",
      "value": "0d27ca72b6f02faf4db95effb18347a7e2fa2def2034707bf9e56fa217879a3b",
      "href": "/ti/ioc/sha256/0d27ca72b6f02faf4db95effb18347a7e2fa2def2034707bf9e56fa217879a3b",
      "context": "Obfuscated payload blob dist/bootstrap.cjs in @tinyfox/shapecheck 0.8.7 (282051 bytes)."
    },
    {
      "kind": "email",
      "value": "glitchpad-revqgz@wshu.net",
      "href": "/ti/ioc/email/glitchpad-revqgz@wshu.net",
      "context": "npm publisher email for the @glitchpad scope (@glitchpad/throttler)."
    },
    {
      "kind": "sha256",
      "value": "68b4fe54a4c05cd0115535ebd4aa8d3cccb03ea5a685f440314814ba1b89e875",
      "href": "/ti/ioc/sha256/68b4fe54a4c05cd0115535ebd4aa8d3cccb03ea5a685f440314814ba1b89e875",
      "context": "Obfuscated payload blob (262934 bytes) shipped BYTE-IDENTICAL in TWO campaign packages: @glitchpad/throttler 2.2.3 (primer.cjs) and @lazyutil/dater 0.9.4 (dist/lib/tzinit.cjs). Confirmed via cmp/sha256 on extracted tarballs. Evidence that the actor reuses identical compiled blobs in at least one case rather than always re-seeding polymorphic per-string-RC4 builds."
    },
    {
      "kind": "email",
      "value": "thymelab-v0et8w@wshu.net",
      "href": "/ti/ioc/email/thymelab-v0et8w@wshu.net",
      "context": "npm publisher email for the @thymelab scope (@thymelab/logfx)."
    },
    {
      "kind": "sha256",
      "value": "4e927f22ad04f4ac9b487ae11412fc2a55210188789ac29f3a47ad77931907a5",
      "href": "/ti/ioc/sha256/4e927f22ad04f4ac9b487ae11412fc2a55210188789ac29f3a47ad77931907a5",
      "context": "Obfuscated payload blob dist/bootstrap.js in @thymelab/logfx 2.15.5 (282151 bytes)."
    },
    {
      "kind": "email",
      "value": "briskforge-5psyxc@wshu.net",
      "href": "/ti/ioc/email/briskforge-5psyxc@wshu.net",
      "context": "npm publisher email for the @briskforge scope (@briskforge/envcheck)."
    },
    {
      "kind": "sha256",
      "value": "26ddfae644673e0ad65b63caaaf67c0f7dc6c2b2b4127bb5271f8d03fb62091a",
      "href": "/ti/ioc/sha256/26ddfae644673e0ad65b63caaaf67c0f7dc6c2b2b4127bb5271f8d03fb62091a",
      "context": "Obfuscated payload blob lib/preflight.js in @briskforge/envcheck 0.5.4 (277356 bytes)."
    },
    {
      "kind": "email",
      "value": "lazyutil-78muyg@wshu.net",
      "href": "/ti/ioc/email/lazyutil-78muyg@wshu.net",
      "context": "npm publisher email for the @lazyutil scope (@lazyutil/dater)."
    },
    {
      "kind": "email",
      "value": "frostnode-gk8pbf@wshu.net",
      "href": "/ti/ioc/email/frostnode-gk8pbf@wshu.net",
      "context": "npm publisher email for the @frostnode scope (@frostnode/waitfor)."
    },
    {
      "kind": "sha256",
      "value": "2de602e6422a991346aaf0b74ed6bd525215f5177b9f7f267ccb4d82e919273d",
      "href": "/ti/ioc/sha256/2de602e6422a991346aaf0b74ed6bd525215f5177b9f7f267ccb4d82e919273d",
      "context": "Obfuscated payload blob dist/cjs/tickinit.cjs in @frostnode/waitfor 0.10.5 (259358 bytes)."
    },
    {
      "kind": "file_path",
      "value": "require(_0x2cb1b0['UGeLH'])",
      "href": "/ti/ioc/file_path/file_path-0b2b81867f4f",
      "context": "Variant of the campaign's dynamically-obscured require fingerprint, found in @frostnode/waitfor dist/cjs/tickinit.cjs. Same technique as the canonical require(_0x45af03['GyrZN']) with a different variable name and proxy key — confirms shared obfuscation template across re-seeded builds."
    },
    {
      "kind": "email",
      "value": "nullzero-rlnozk@wshu.net",
      "href": "/ti/ioc/email/nullzero-rlnozk@wshu.net",
      "context": "npm publisher email for the @nullzero scope (@nullzero/urlcat, flagged version unpublished before inspection)."
    },
    {
      "kind": "email",
      "value": "gleamkit-23vnic@wshu.net",
      "href": "/ti/ioc/email/gleamkit-23vnic@wshu.net",
      "context": "npm publisher email for the @gleamkit scope (@gleamkit/probe scope-reservation stub). Same <scope>-<6char>@wshu.net burner pattern; wshu.net is a public disposable-email provider (supporting signal only)."
    }
  ],
  "ttps": [
    {
      "name": "Compromise Software Supply Chain",
      "mitre_attack_id": "T1195.002",
      "href": "/ti/ttps/T1195.002"
    },
    {
      "name": "Command and Scripting Interpreter: JavaScript",
      "mitre_attack_id": "T1059.007",
      "href": "/ti/ttps/T1059.007"
    },
    {
      "name": "Obfuscated Files or Information",
      "mitre_attack_id": "T1027",
      "href": "/ti/ttps/T1027"
    },
    {
      "name": "Credentials from Password Stores: Web Browsers",
      "mitre_attack_id": "T1555.003",
      "href": "/ti/ttps/T1555.003"
    },
    {
      "name": "Steal Web Session Cookie",
      "mitre_attack_id": "T1539",
      "href": "/ti/ttps/T1539"
    },
    {
      "name": "Application Layer Protocol: Web Protocols",
      "mitre_attack_id": "T1071.001",
      "href": "/ti/ttps/T1071.001"
    },
    {
      "name": "Ingress Tool Transfer",
      "mitre_attack_id": "T1105",
      "href": "/ti/ttps/T1105"
    },
    {
      "name": "Create or Modify System Process: Systemd Service",
      "mitre_attack_id": "T1543.002",
      "href": "/ti/ttps/T1543.002"
    },
    {
      "name": "Web Service",
      "mitre_attack_id": "T1102",
      "href": "/ti/ttps/T1102"
    },
    {
      "name": "Unsecured Credentials: Credentials In Files",
      "mitre_attack_id": "T1552.001",
      "href": "/ti/ttps/T1552.001"
    },
    {
      "name": "Credentials from Password Stores",
      "mitre_attack_id": "T1555",
      "href": "/ti/ttps/T1555"
    },
    {
      "name": "Masquerading",
      "mitre_attack_id": "T1036",
      "href": "/ti/ttps/T1036"
    }
  ],
  "related_campaigns": [
    {
      "name": "No Specific Campaign",
      "slug": "no-specific-campaign",
      "href": "/ti/campaigns/no-specific-campaign",
      "relationship": "variant-of"
    }
  ],
  "reports": [
    {
      "title": "The wshu.net npm Campaign Steals Browser Logins on Install",
      "url": "https://safedep.io/wshu-net-npm-credential-stealer-campaign",
      "published_at": "2026-06-23"
    }
  ]
}