- Multiple campaigns have abused trusted React Native npm packages and tooling, from UI components to CLI utilities, via account takeover and typosquatting.
- Attackers increasingly deploy sophisticated multi-stage malware using Solana or decentralized C2, targeting developer machines, CI pipelines and wallet or credential data.
- Security vendors now rely on AI analysis, cooldown checks and hardened CI egress controls to catch and contain these supply-chain attacks in minutes.
- React Native teams must combine strict dependency hygiene, npm 2FA, lockfiles and continuous monitoring to meaningfully reduce supply-chain risk.

React Native has become a go‑to framework for building mobile apps, which makes its npm ecosystem an extremely attractive target for attackers looking to compromise developer machines and CI pipelines. Over the last few years, several highly sophisticated campaigns have abused trusted React Native packages, popular tooling around the framework, and even typosquatted utilities to plant malware, steal credentials, exfiltrate wallets and sabotage JavaScript projects at scale.
If you build or maintain React Native apps today, it’s no longer enough to just “npm install and hope for the best”. Multiple threat actors are systematically abusing npm, targeting everything from UI components to CLI tools, and even the transitive dependency graph that hides deep in your lockfiles. This article walks through the major known incidents, dissects how the malware works, and lays out pragmatic steps you can take to reduce the blast radius on your own development environment.
Account takeover and malware in React Native input components
One of the most alarming supply-chain incidents in the React Native world hit two very common UI components for phone and country selection: react-native-international-phone-number and react-native-country-select. Both packages, maintained by the same author (@AstrOOnauta, npm user astroonauta), accumulated tens of thousands of weekly downloads and are embedded in many production mobile apps.
On March 16, 2026, StepSecurity’s AI-based Package Analyst was the first to spot that new versions of these libraries had suddenly gained install-time malware. The immediately compromised releases were react-native-international-phone-number@0.11.8 and react-native-country-select@0.3.91. The last confirmed clean versions at that point were 0.11.7 and 0.3.9 respectively.
The initial backdoor (Wave 1) was brutally simple: a new preinstall script and a heavily obfuscated install.js file bundled into the tarball. The malicious package.json snippet looked like this:
"scripts": { "preinstall": "node install.js" }
Because npm lifecycle scripts run automatically on npm install, anyone pulling these versions – locally or in CI – ran the malware without importing any code. There were no corresponding Git tags, releases, or CI workflow runs for the compromised versions, and the gitHead matched the previous good release, a strong indicator that the attacker had gained direct publish access to the maintainer’s npm account instead of modifying the GitHub repo.
Download data around that time underlines how bad this could have been: roughly 9,000 weekly downloads for react-native-country-select and over 20,000 for react-native-international-phone-number, adding up to more than 130,000 downloads per month between the two. This is precisely the kind of high‑volume, low‑visibility dependency that silently lands on thousands of developer and CI machines.
Three-wave attack: from obvious preinstall to stealthy dependency chains
The campaign against these React Native packages unfolded in three distinct waves, each iteration more evasive than the last while reusing the same core malware. StepSecurity tracked the evolution in near real time and coordinated with the maintainer, but the attacker repeatedly regained or retained access to the compromised npm account.
Wave 1 (March 16, 2026) centered on the direct preinstall hook in both packages. Within about five minutes of publication, StepSecurity’s AI flagged the new releases as critical, and issues were opened on GitHub: #165 for react-native-international-phone-number and #11 for react-native-country-select. The maintainer responded quickly, deprecating the malicious versions and pushing a clean react-native-country-select@0.4.0. Total time from publish to deprecation was around 2 hours and 21 minutes – fast by ecosystem standards.
Despite this, the attacker never lost control of the npm credentials, leading to Wave 2 on March 17. Instead of dropping an obvious script into the main packages again, the threat actor staged two new scoped packages to act as hidden infrastructure:
@usebioerhold8733/s-format@2.0.1– a hollow clone ofstring-formatwith apostinstall: "node init.js"script but missing theinit.jsfile, so the hook fails silently.@agnoliaarisian7180/string-argv@0.3.0– a near-empty package (README, LICENSE, package.json) whose only real purpose was to depend on@usebioerhold8733/s-format, with a ProtonMail-based maintainer address.
Later that evening, react-native-international-phone-number@0.12.1 was published with @agnoliaarisian7180/string-argv@0.3.0 added as a new dependency, again without any GitHub Actions activity. At that point the chain was staged but inert, waiting for the payload to be switched on. When StepSecurity reported the anomaly, the maintainer confirmed what was already obvious from the artefacts: “my npm account was attacked and the library was taken over”.
Wave 3 (March 18) switched the staged infrastructure into an active multi-layer malware delivery chain and then refined it in rapid succession. New versions of both relay packages and the main library were pushed within under an hour, with the attacker iterating on how the payload was launched.
The final chain looked like this:
react-native-international-phone-number@0.12.2/0.12.3 → @agnoliaarisian7180/string-argv@latest → @usebioerhold8733/s-format@latest → postinstall → node child.js → init.js (malware)
The attacker first turned on the payload in @usebioerhold8733/s-format@2.0.2 by adding a big, obfuscated init.js file that was byte‑for‑byte identical to the previous install.js from Wave 1. They then changed the postinstall to call child.js instead of init.js, published 2.0.3 with the script missing (another dry run), and finally shipped 2.0.4 with a tiny child.js loader that simply checks for init.js and executes it via child_process.exec while discarding errors and stderr output.
At the same time, @agnoliaarisian7180/string-argv@0.3.1 switched its dependency on s-format from a pinned version to "latest", and react-native-international-phone-number@0.12.2 did the same with string-argv. This created a self-updating malicious chain where every install of the main package automatically pulled the newest payload version.
Finally, react-native-international-phone-number@0.12.3 removed the now-unnecessary preinstall hook (to look cleaner), kept the malicious dependency chain, and changed the npm maintainer email to yet another ProtonMail account not owned by the original author. That was a clear sign the attacker was consolidating persistent control over the npm identity, not just opportunistically reusing a leaked token.
Inside the Solana-backed malware targeting React Native developers
Under the hood, the payload running in all three waves was the same sophisticated multi‑stage malware that abuses the Solana blockchain as a dynamic command-and-control channel. The delivery mechanism kept changing, but the “weapon” stayed identical across all iterations, down to being byte‑for‑byte the same file when transplanted from Wave 1 into the Wave 3 infrastructure.
The script kicks off with a deliberate 10‑second delay using setTimeout, a classic sandbox-evasion trick. Many automated sandboxes and security tools give scripts only a short execution window before deciding nothing suspicious happened, so the malware simply waits them out before doing anything interesting.
Next, it performs a geo‑filter to avoid infecting systems in Russia and parts of the CIS. It inspects environment variables like LANG, LANGUAGE, LC_ALL, host user information, the system timezone and even raw UTC offsets, looking for values that indicate a Russian locale (such as ru_RU or Russian) or one of a list of Russian/CIS time zones. If any of these match, the script exits immediately and quietly.
Only if the environment passes that check does the malware start talking to the Solana blockchain. It holds a hard-coded wallet address and queries it via the getSignaturesForAddress JSON‑RPC method across nine different Solana RPC endpoints hosted by various providers. This design gives the attacker high availability and makes simple domain or IP blocking ineffective.
The trick is that the attacker hides the next-stage payload URL inside the memo field of Solana transactions to that wallet. The memo stores a blob of base64-encoded JSON whose link field contains the URL of the next stage. By posting a new transaction, the operator can rotate the payload URL at any time without modifying the published npm packages.
Once the URL is extracted, the malware performs an HTTP request to the attacker’s server at http://45.32.150.251/, sending the OS type in a custom os header so the C2 can return platform‑specific binaries. The response body carries the encrypted payload, but the AES‑256 key and IV needed to decrypt it are sent only in HTTP headers (secretkey and ivbase64), so any cached or intercepted body data is useless on its own.
The decrypted second stage never touches disk; it is executed in memory with eval(atob(...)) on Unix‑like systems or via vm.Script on Windows with full access to Node internals. Afterwards, the malware drops a ~/init.json marker file that stores a timestamp and a unique identifier so the same machine is not re‑infected more than once every 48 hours. That rate limiting dramatically cuts noise and gives defenders fewer behavioural indicators to latch onto.
The AES‑decrypted third‑stage payload, recovered by researchers by replaying the same Solana and HTTP steps, is a Windows-centric credential and wallet stealer plus loader. It establishes persistence with schtasks and the Run registry key, downloads additional encrypted modules from 45.32.150.251, and exfiltrates the resulting loot to an IP in the 217.69.3.x range.
This payload hunts down data from desktop wallets and browser extensions such as MetaMask, Phantom, Exodus, Atomic, Guarda, Coinomi, Daedalus, OKX Wallet, Trust Wallet, Braavos and more, walking through browser profile folders and local wallet directories after force‑closing Chrome and Firefox. On top of that, it pulls npm tokens and GitHub credentials directly from local configuration and credential helpers, turning compromised developer boxes into perfect launch pads for further supply-chain attacks.
Notably, the malware even downloads its own Node.js runtimes (v22.9.0) for both x86 and x64 into %APPDATA%\_node_x86 and %APPDATA%\_node_x64, ensuring it has a consistent execution environment even when Node is not installed on the target system.
Links to ForceMemo and the GlassWorm threat actor
The technical fingerprint of this React Native npm incident lines up almost perfectly with a previous campaign dubbed “ForceMemo”, which compromised hundreds of Python repositories on GitHub. Both operations used Solana as a dead‑drop C2, the same group of nine RPC endpoints, the same JSON memo format with a link field, identical Russia/CIS geo‑filtering logic, the same ~/init.json persistence lock and even similar infrastructure ranges hosted on Vultr.
Although the Solana wallet addresses differ between the two campaigns, everything else points to a single highly capable actor, believed to be the group known as GlassWorm. ForceMemo targeted developers through poisoned GitHub repos, while the React Native incident did so through npm packages and their dependency chains. The strategy is clear: reuse a sophisticated, modular malware framework but plug it into different distribution channels to reach as many development environments as possible.
Other malicious npm campaigns around React Native and JavaScript
The AstrOOnauta compromise is only one piece of a broader wave of npm‑based attacks that affect React Native apps directly or indirectly. Several security vendors have documented parallel campaigns focusing on React Native UI libraries, core CLI tooling, and even generic build plugins that many React Native codebases depend on.
Aikido Security uncovered a major supply‑chain operation in June 2025 that backdoored at least 16 React Native-related packages under the @react-native-aria/* scope plus @gluestack-ui/utils, collectively serving around one million weekly downloads. The initial breach happened on June 6, 2025, starting with @react-native-aria/focus@0.2.10, then quickly expanded across additional focus, overlay, interaction, toggle, switch, checkbox, radio, button, menu, listbox, tabs, combobox, disclosure, slider, separator packages and the GlueStack utilities on June 7.
The malware in that campaign was a Remote Access Trojan (RAT) tailored to Windows environments, persisting under %LOCALAPPDATA%\Programs\Python\Python3127 and connecting to C2 servers at 136.0.9[.]8 and 85.239.62[.]36. Its capabilities included arbitrary command execution, file upload/download and long‑term remote access. Persistence meant that simply upgrading to a clean version of the React Native library did not clean up already infected machines.
Another long‑running campaign exposed by Socket’s Threat Research Team used typosquatting and mimicry to plant destructive packages that explicitly target popular JavaScript frameworks such as React, Vue, Vite and Quill. The threat actor, using the npm alias xuxingfeng, published a mix of legitimate and malicious packages over more than two years, creating a surface impression of being a trustworthy maintainer.
Packages like vite-plugin-bomb, vite-plugin-bomb-extend, vite-plugin-react-extend, vite-plugin-vue-extend and vue-plugin-bomb were designed not to steal data but to actively corrupt or destroy projects. They implemented multi‑phase attacks triggered by specific dates, deleting critical framework files under node_modules (Vue, React, Vite, TypeScript, Ant Design Vue, Pinia, ECharts and more), sometimes paired with forced system shutdowns every second using shutdown -s -t 5.
One particularly nasty package, js-hood, tampered with core JavaScript prototypes such as Array.prototype.filter, map, push, pop and multiple String methods, replacing them with functions that look syntactically valid but return random data. This results in applications that continue to run yet produce corrupt, non‑deterministic results that are extremely hard to debug.
The quill-image-downloader series went in another direction, focusing on client‑side storage sabotage. It shipped a three‑file architecture that, after a specified activation date, iterates over all keys in localStorage, sessionStorage and cookies, and then partially scrambles their values with random characters while preserving structure. Authentication tokens, shopping carts, user preferences and any browser‑side state become subtly corrupted, causing intermittent failures that many teams would initially attribute to application bugs.
Separate research from OP Innovate uncovered a cluster of ten malicious npm packages that impersonated well‑known libraries like TypeScript, discord.js, ethers.js, nodemon, react-router-dom and zustand. Once installed, these packages present a fake CAPTCHA window, fingerprint the host and download a large cross‑platform info‑stealer from a C2 at 195.133.79.43, again with explicit support for Windows, macOS and Linux.
Finally, the CanisterWorm campaign, detailed by Aikido, demonstrated just how far attackers are willing to go in exploiting npm as a delivery vehicle. Over 135 packages from a compromised publisher account were weaponised with install‑time scripts that execute before any of your application code or build steps. Later stages behave differently depending on whether they land on a local dev box, a CI job, or a containerised build node, and they talk to a decentralized Internet Computer (ICP) canister that functions as a stealth C2 – allowing operators to change behaviour on the fly without ever touching the npm registry again.
Critical vulnerabilities in React Native tooling: the Community CLI RCE
Not all React Native security risks come from outright malicious packages; some stem from serious vulnerabilities in widely used tools. One notable case is CVE‑2025‑11953 in the React Native Community CLI, a package pulled millions of times each week by developers on Windows, macOS and Linux.
This flaw allowed unauthenticated Remote Code Execution (RCE) via crafted POST requests to the local development server started by the CLI. Because many developers expose their metro/dev servers on the network for debugging or mobile device testing, a nearby attacker (or someone who can route traffic to those ports) could run arbitrary commands on the developer’s machine.
The impact goes well beyond one developer workstation: once an attacker has code execution on a dev box, they can pivot into corporate networks, scrape credentials, poison builds or manipulate CI/CD pipelines that sync from that machine. It’s a textbook example of how “just a local dev tool” is part of your production attack surface when you work on cloud-connected systems.
The recommended mitigation is straightforward but non‑negotiable: update to React Native Community CLI 12.5.1 or higher, audit logs for suspicious POST requests or unexpected processes spun up by the dev server, restrict access to local servers and fold dev tooling into your threat detection strategy. Treat any DevOps or developer endpoint as a high‑value target, because that is exactly how modern attackers see it.
How defenders responded: AI analysis, cooldowns and hardened CI
The upside in these stories is that the security community is getting faster and more sophisticated at catching supply-chain threats against React Native and the broader JavaScript space. Tools like StepSecurity, Socket and Aikido Security invest heavily in behavioural analysis, automated diffing and machine‑learning models that scan new npm releases within minutes of publication.
In the AstrOOnauta attack, StepSecurity’s AI Package Analyst detected malicious versions in under five minutes, opened GitHub issues with full technical breakdowns, and later reported the attacker’s scoped infrastructure packages to npm for removal. The team documented each wave, tracked git heads, analysed obfuscated code, showed proof of Solana C2 usage and gave step‑by‑step remediation guidance to the maintainer.
Beyond detection, preventive controls are starting to gain traction in CI pipelines. For example, StepSecurity’s npm Package Cooldown Check lets organisations block dependencies that were published only hours ago, buying time for scanners and humans to inspect them. Their compromised‑updates check cross‑references a constantly updated feed of known‑bad packages and fails PRs that attempt to add or upgrade to them.
Network‑aware tooling such as Harden‑Runner restricts outbound connections in GitHub Actions and other CI jobs to an allowlist of expected endpoints. In a world where malware fetches payloads from Solana RPC nodes, Google Calendar URLs, Vultr IP ranges or ICP canisters, locking down egress from your build systems can be the difference between a bad package diff and a full‑blown intrusion.
On the response side, features like organisation‑wide package search and threat centres help teams quickly map blast radius. As soon as a compromised React Native package or plugin is identified, security teams can see which repositories, branches and lockfiles include it, what jobs executed it and which machines talked to suspicious IPs – and then prioritise remediation accordingly across dozens or hundreds of codebases.
Practical actions for React Native teams facing npm malware
For React Native developers and security engineers alike, defending against npm‑level attacks is about combining hygiene on individual machines with guardrails in CI/CD and dependency management. No single control will save you, but layered defences dramatically lower the odds that a malicious package turns into a full compromise.
If you use the compromised packages mentioned earlier, there are some immediate checks to perform. For the AstrOOnauta incident, pin react-native-international-phone-number to version 0.11.7 and react-native-country-select to 0.4.0, avoiding all versions flagged as malicious or resolving to @latest that currently maps to a compromised release.
Inspect your home directory for a file named init.json under the user profile (for example ~/init.json on Unix and ~\init.json on Windows). Its presence suggests the Solana‑based malware executed at least once. Also audit outbound network logs from developer workstations and CI runners for connections to 45.32.150.251, the Solana RPC endpoints used in the campaigns, or the other C2 addresses cited earlier (e.g. 136.0.9[.]8, 85.239.62[.]36, 195.133.79.43, 217.69.3.152).
Check your node_modules and lockfiles for tell‑tale dependencies like @agnoliaarisian7180/string-argv, @usebioerhold8733/s-format and the malicious @react-native-aria/* or @gluestack-ui/utils versions listed in advisories. If you find any of them, treat the machine as potentially compromised and rotate all sensitive credentials: npm tokens, GitHub access tokens, SSH keys, cloud provider keys and any secrets present in .env or configuration files at install time.
Looking forward, tighten your supply‑chain posture for React Native work: always commit and enforce lockfiles (package-lock.json, yarn.lock, pnpm-lock.yaml), enable 2FA on all npm accounts with publish rights, and configure your CI to fail builds when new dependencies appear without review. Consider running with --ignore-scripts when installing third‑party packages in untrusted contexts, and hook dependency-scanning tools into both local workflows and CI.
Finally, treat development environments – especially those used for React Native apps that bridge mobile, web and backend APIs – as part of your production attack surface. Whether the threat is an account-takeover dropping Solana‑backed malware into a phone input component, a typosquatted Vite plugin deleting React from node_modules, a malicious Quill integration scrambling client‑side storage, or an RCE in the React Native Community CLI, the common thread is that attackers now see developer tooling as one of the most efficient paths into your organisation’s crown jewels.

