nos-rescue
Rescue staked NOS — and every other SOL / SPL token — from a compromised Solana wallet, even though the attacker holds the same private key.
- Download the one-file app and open it in your browser (double-click it — it runs entirely on your machine). We recommend this over the hosted copy: a local file can't silently change under you, and you can verify its checksum.
- Create a fresh fee-payer wallet and fund it with a little SOL (~0.1 is plenty).
- Pick a safe destination address (a wallet the attacker has no access to — ideally brand new).
- Paste the compromised key, the fee-payer key, and the safe address. Click Start rescue and keep the tab open.
What it does
The trick: a separate, uncompromised wallet pays every transaction fee and every rent deposit, so the compromised wallet never needs — and never keeps — any SOL. Without SOL the attacker cannot broadcast a single transaction. The tool then races them:
- Unstakes immediately. Nosana stakes vest linearly after unstaking; whoever holds the key can withdraw each released slice, first-come-first-served.
- Sweeps continuously. A websocket watcher moves any SOL or token out of the hacked wallet in well under a second, starving the attacker of fee money. This is the real defense.
- Withdraws released NOS straight to your safe wallet as it vests — the on-chain withdraw names the destination, so funds never pass through the hacked wallet.
- Claims pending rewards to the safe wallet and reclaims every rent deposit from closed token accounts along the way.
The three wallets
| Role | What it is | Needs SOL? |
|---|---|---|
| Compromised | The hacked wallet holding the stake. You provide its key. | No |
| Fee payer | A separate, clean wallet you control. Pays all fees + rent. | Yes — fund it with some SOL |
| Safe | Destination address. Receives all rescued NOS/SOL/tokens. | No |
Keys are accepted as a base58 private key or a keypair.json array (Solana CLI format).
Quickstart
Option A — one HTML file (easiest)
- Download
nos-rescue.html(also attached to every GitHub release). - Double-click it. It opens in your browser and works from
file://— no install, no server, no network access except the Solana RPC you choose. - Fill in the three wallets, optionally tick Dry run first, then Start rescue. Keep the tab open — the watcher loop lives there.
If your browser refuses to run it from file://, serve it locally instead: npx serve in the folder containing the file, then open the printed URL.
Option B — npx (terminal, best for unattended runs)
# Read-only status of any wallet — no keys needed
npx nos-rescue status <WALLET_ADDRESS>
# Full rescue daemon
npx nos-rescue rescue \
--rpc "https://your-fast-rpc" \
--safe <SAFE_ADDRESS> \
--hacked-key ./hacked.json \
--payer-key ./payer.json
Requires Node.js ≥ 20.18. Run it on a server close to a fast RPC for the best race position.
CLI reference
Global options (all commands)
| Flag | Env var | Meaning |
|---|---|---|
--rpc <url> | NOS_RESCUE_RPC | Solana RPC endpoint. A fast private RPC is strongly recommended. |
--ws <url> | NOS_RESCUE_WS | Websocket endpoint. Default: the RPC URL with ws(s)://. |
--network <net> | — | mainnet (default) or devnet. |
--hacked-key <key> | NOS_RESCUE_HACKED_KEY | Compromised wallet: base58 key or keypair.json path. |
--payer-key <key> | NOS_RESCUE_PAYER_KEY | Fee payer wallet: base58 key or keypair.json path. |
--safe <address> | NOS_RESCUE_SAFE | Safe destination wallet address. |
--dry-run | — | Simulate every transaction instead of sending. Nothing moves on-chain. |
Keys omitted from flags and env vars are asked for with a hidden interactive prompt — the safest option, since flags land in shell history.
status <owner>
Read-only view of a wallet's SOL/NOS balances, stake account, vesting timeline, and pending rewards. No keys needed.
npx nos-rescue status 9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin
rescue
The full daemon: sweeps continuously (websocket-triggered, interval polling as backup), unstakes, withdraws released NOS on a cadence, closes accounts at full vest, and keeps sweeping forever.
| Option | Default | Meaning |
|---|---|---|
--sweep-interval <s> | 15 | Backup poll cadence; websocket events sweep instantly regardless. |
--withdraw-interval <s> | 3600 | Minimum seconds between partial withdrawals. 0 = only withdraw at full vest. |
--no-auto-withdraw | — | Never auto-withdraw; sweep only. Use the withdraw command manually. |
--min-withdraw <nos> | 0 | Skip partial withdrawals smaller than this many NOS. |
export NOS_RESCUE_RPC="https://your-fast-rpc"
export NOS_RESCUE_SAFE="<SAFE_ADDRESS>"
export NOS_RESCUE_HACKED_KEY="<base58 or path>"
export NOS_RESCUE_PAYER_KEY="<base58 or path>"
npx nos-rescue rescue
unstake
One-shot: claims pending rewards to the safe wallet, closes the reward account, and unstakes — all in one atomic transaction.
npx nos-rescue unstake --safe <SAFE> --hacked-key ./hacked.json --payer-key ./payer.json
withdraw
One-shot: withdraws the currently released NOS to the safe wallet, and closes the stake account if fully vested.
npx nos-rescue withdraw --safe <SAFE> --hacked-key ./hacked.json --payer-key ./payer.json
sweep
Moves all SOL and SPL/Token-2022 balances out of the compromised wallet, closing drained token accounts so their rent goes to the safe wallet too. Add --watch to keep watching and sweeping.
npx nos-rescue sweep --watch --interval 15 \
--safe <SAFE> --hacked-key ./hacked.json --payer-key ./payer.json
Dry run
Add --dry-run to any command to build and sign every transaction exactly as for real, run it through simulateTransaction, and log the outcome — nothing is broadcast. rescue --dry-run does one full pass and exits.
npx nos-rescue --dry-run rescue
RPC recommendations
Everything works on the default public RPC, but public RPCs are slow and rate-limited — in a race
against an attacker that can cost you vesting slices. Use a fast private RPC: the free
tiers of Helius, QuickNode, or Triton all work. Pass it with --rpc /
NOS_RESCUE_RPC (or the RPC field in the web UI). If your provider uses a separate
websocket URL, pass --ws / NOS_RESCUE_WS.
Security notes
- Keys never leave your machine. In the web UI they are held only in the tab's memory and sent nowhere except as signed transactions to your chosen RPC. The CLI keeps them in process memory and writes nothing to disk.
- Prefer the downloaded file over the hosted app, and prefer env vars or the interactive prompt over CLI flags (flags land in shell history).
- Verify the download. The expected SHA-256 of
nos-rescue.htmlis published next to the file and in every GitHub release's notes. Check yours:sha256sum nos-rescue.html(macOS:shasum -a 256). - Triple-check the safe address. This tool moves everything out of the compromised wallet to that address, irreversibly. Make sure it's a wallet the attacker cannot access — ideally a brand-new one.
- Run it on a machine you trust — malware on the machine defeats any wallet tool.