A privacy audit tool for Bitcoin wallets. Stealth analyzes the transaction history of a wallet descriptor and surfaces privacy findings from real on-chain heuristics.
Paste a Bitcoin wallet descriptor into the input screen and click Analyze. Stealth derives addresses from the descriptor, scans wallet-related chain history, and returns a report with structured findings and warnings.
Stealth's source-of-truth detector is backend/script/detect.py. The frontend renders the type values emitted by that script.
| Type | Meaning |
|---|---|
ADDRESS_REUSE |
Address received funds in multiple transactions, linking history and balances. |
CIOH |
Multi-input linkage (Common Input Ownership Heuristic) across co-spent inputs. |
DUST |
Dust output detection (current or historical). |
DUST_SPENDING |
Dust input spent with normal inputs, actively linking clusters. |
CHANGE_DETECTION |
Change output appears trivially identifiable through heuristics. |
CONSOLIDATION |
UTXO created from many-input consolidation transaction. |
SCRIPT_TYPE_MIXING |
Mixed input script families in one spend (strong fingerprint). |
CLUSTER_MERGE |
Inputs from previously separate funding chains merged in one tx. |
UTXO_AGE_SPREAD |
Large age spread across UTXOs reveals dormancy/lookback patterns. |
EXCHANGE_ORIGIN |
Probable exchange batch-withdrawal origin. |
TAINTED_UTXO_MERGE |
Tainted and clean inputs merged, propagating taint. |
BEHAVIORAL_FINGERPRINT |
Consistent transaction behavior reveals wallet/user fingerprint. |
| Type | Meaning |
|---|---|
DORMANT_UTXOS |
Dormant/aged UTXO pattern warning. |
DIRECT_TAINT |
Direct receipt from a known risky source. |
severity values are emitted as uppercase strings (for example LOW, MEDIUM, HIGH, and CRITICAL).
- Open the application.
- On the first screen, paste your wallet descriptor into the input field.
- Supported formats:
wpkh(...),pkh(...),sh(wpkh(...)),tr(...), and multisig variants.
- Supported formats:
- Click Analyze.
- Review the results:
- Summary counters for findings, warnings, and transactions analyzed.
- Collapsible finding/warning cards with type, severity, description, and structured evidence.
| Dependency | Version | Purpose |
|---|---|---|
| Bitcoin Core | ≥ 26 | Local regtest node |
| Python | ≥ 3.10 | Analysis engine (detect.py) |
| Java | 21 | Quarkus backend |
| Node.js + yarn | ≥ 18 | React frontend |
git clone https://github.com/LORDBABUINO/stealth.git
cd stealthEdit backend/script/config.ini to match your node:
[bitcoin]
network = regtest
cli = bitcoin-cli
# Data directory — matches setup.sh (relative to config.ini location)
datadir = bitcoin-data
# Optional RPC overrides (leave blank to use cookie auth from the datadir)
rpchost =
rpcport =
rpcuser =
rpcpassword =cd backend/script
./setup.sh # starts bitcoind, creates wallets, mines 110 blocksPass --fresh to wipe the chain and start from genesis.
python3 reproduce.pyThis script sends transactions between the test wallets to reproduce all 12 detector finding types. The application will return no findings without this step, since a freshly mined chain has no transaction history to analyze.
After it runs, get a descriptor to paste into the app:
bitcoin-cli -datadir=bitcoin-data -regtest -rpcwallet=alice listdescriptors | python3 -c \
"import sys,json; d=json.load(sys.stdin)['descriptors']; print(d[0]['desc'])"Copy the output and use it as the descriptor in the application.
cd backend/src/StealthBackend
./mvnw quarkus:devThe API will be available at http://localhost:8080.
cd frontend
yarn install
yarn devOpen http://localhost:5173 in your browser.
- Paste a wallet descriptor into the input field (e.g.
wpkh([fp/84h/0h/0h]xpub.../0/*)). - Click Analyze — the frontend calls
GET /api/wallet/scan?descriptor=…on the backend, which runsdetect.pyagainst your local regtest node. - Review the report:
findings[]andwarnings[]entries each includetype,severity,description, and optionaldetails.- The summary panel shows
findings,warnings, and whether the scan isclean.
stealth/
├── frontend/ # React + Vite UI
│ └── src/
│ ├── components/ # FindingCard, VulnerabilityBadge
│ ├── screens/ # InputScreen, LoadingScreen, ReportScreen
│ └── services/ # walletService.js (API client)
├── backend/
│ ├── script/ # Python scripts + regtest data
│ │ ├── setup.sh # Bootstrap bitcoind regtest
│ │ ├── reproduce.py # Create 12 vulnerability scenarios
│ │ ├── detect.py # Privacy vulnerability detector
│ │ ├── bitcoin_rpc.py # bitcoin-cli wrapper
│ │ ├── config.ini # Connection config (datadir, network)
│ │ └── bitcoin-data/ # Regtest chain data (gitignored)
│ └── src/StealthBackend/ # Quarkus Java REST API (single /api/wallet/scan endpoint)
└── slides/ # Slidev pitch presentation
Stealth does not store, log, or transmit your wallet descriptor or any derived keys. All analysis is read-only and uses publicly available on-chain data. However, querying a third-party node or API for your transaction history may itself reveal your addresses to that service. For maximum privacy, point the backend at your own Bitcoin node.