anticsdecoded|Portfolio
SEC|2026
/audits / ZANO.cpp
cat /audits/ZANO.cpp
NODE: BOUNTY

Privacy L1 (CryptoNote / Zarcanum)

// engagement
protocolZano
categoryPrivacy L1 (CryptoNote / Zarcanum)
kindbounty · Immunefi
date2026-04
duration2 weeks
languageC++
chainsZano
nSLOC4,320
// findingsNODE: 4 FND
critical1
high1
medium0
low2
info0
gas0
// summary

Immunefi review of the Zano privacy L1 (CryptoNote / Zarcanum lineage) C++ daemon (zanod) and wallet, spanning the admin RPC surface, the mempool acceptance path, the wallet↔daemon transport, and the wallet RPC authentication layer.

// methodology
  • Manual review
  • PoC development
  • RPC/P2P analysis
// scope
pathnsloc
src/rpc/core_rpc_server.cpp1,900
src/currency_core/tx_pool.cpp820
src/wallet/wallet_rpc_server.cpp1,240
src/wallet/core_default_rpc_proxy.cpp360
total4,320
// findings
C-01criticalacknowledged

Unauthenticated `reset_transaction_pool` admin RPC purges the mempool

The handler calls `purge_transactions()` with no token, header, or caller check, so against an admin-API node bound to a reachable interface any remote party can clear the entire mempool with a single unauthenticated POST — and repeat it to suppress transactions and stall confirmations.

H-01highacknowledged

Unbounded transaction acceptance in `tx_pool` enables resource-exhaustion DoS

`tx_memory_pool::add_tx` admits transactions with no early upper bound on size, input/output count, or Zarcanum proof complexity, so one crafted oversized transaction (200+ inputs/outputs) is accepted and only then verified — spiking node CPU over 30% and degrading RPC responsiveness; repeated submissions amplify it.

L-01lowacknowledged

Wallet↔daemon HTTPS connection performs no TLS certificate validation

On the `https` daemon path the wallet enables SSL but installs no certificate verification (no CA, hostname, or expiry check), so an attacker on the network path can transparently MITM the wallet↔daemon channel and read or tamper with all RPC traffic.

L-02lowacknowledged

JWT anti-replay salts are not persisted, enabling RPC command replay across restart

Consumed JWT anti-replay salts (`m_jwt_used_salts`) live only in process memory, so after a wallet-RPC restart a previously-seen, still-unexpired token plus its exact request body can be replayed to re-execute sensitive methods such as `transfer` and `sweep_below`.