← Back to Research
Research · August 10, 2026

Zebra getaddressutxos RPC response amplification

Simon Morley·3 min read

Zebra's getaddressutxos RPC method returns all unspent outputs for a transparent address without pagination, enabling an unauthenticated attacker to amplify a small request into a large response (≈2,033×) by pre-seeding the address with dust UTXOs.

Why this matters

Operators exposing Zebra's RPC interface face a bandwidth and memory exhaustion risk. Unlike getaddressbalance (which returns a scalar), getaddressutxos scales linearly with the number of UTXOs. A naïve request-count rate limit is insufficient because a single request can consume significant resources, bounded per query only by rpc.max_response_body_size (default 50 MiB). While the sibling method getaddresstxids exhibits similar unpaginated behaviour, getaddressutxos presents a higher per-item byte size (~235 B/UTXO vs ~67 B/txid), resulting in greater amplification potential for the same number of seeded items.

How the attack works

The attacker controls a transparent address and seeds it with N cheap coinbase UTXOs. They then invoke the getaddressutxos method via zebra-rpc. The handler (methods.rszebra_state::ReadRequest::UtxosByAddresses) retrieves all UTXOs for that address and constructs a JSON response containing one entry per UTXO (fields: address, txid, outputIndex, script, satoshis, height). The response size scales linearly with N. The request is unauthenticated and small (~116 B), while the response is bounded only by rpc.max_response_body_size.

Affected systems

  • Severity: Medium (per NR-2026-061).
  • Implementation: Zebra (ZcashFoundation/zebra)
  • Component: zebra-rpc
  • Method: getaddressutxos
  • Version: Observed on Zebra 4.2.0 (Regtest). The behaviour is documented unpaginated method semantics, not a version-specific regression.

Evidence

  • Publicly documented: The Zcash RPC documentation lists getaddressutxos as returning a list of UTXOs without pagination parameters.
  • Independently reproduced by NullRabbit: A reproducer (zcash_zebra_rpc_amp.py) was run against a self-owned Zebra 4.2.0 Regtest node.
  • Measured under controlled conditions:
    • Environment: Zebra 4.2.0 Regtest, loopback, N=1000 coinbase UTXOs at a controlled transparent address.
    • Result: ~116 B request → ~236 KB response.
    • Amplification: ≈2,033×.
    • Linearity: Confirmed at N=200 (406×) and N=1000 (2,033×).
    • Control: getaddressbalance returned a scalar (≈1× amplification).

Operator actions

  • Mitigation: Paginate or cap the result count for address-index RPCs. Lower rpc.max_response_body_size. Implement rate limiting per source IP. Ensure the RPC is bound to loopback or placed behind an authenticating gateway.
  • Detection: Monitor for spikes in RPC response sizes or high bandwidth usage associated with getaddressutxos calls to specific transparent addresses.

Canonical references

Related attacks

  • Sibling finding (same advisory): zcash_zebra_getaddresstxids_response_amp (method: getaddresstxids). This method also lacks pagination but returns smaller per-item payloads (~67 B/txid vs ~235 B/UTXO), resulting in lower measured amplification (~578× at N=1000).
  • Same technique (NRDAX-T0329): Other Zebra instances such as zcash_zebra_getblocktemplate_response_amp and zcash_zebra_getrawmempool_verbose_response_amp exist within the same technique family.

Subscription call to action

Track attacks affecting Zebra.


Analysis plus reproducer. No weaponised proof-of-concept code.

zcashzebrajson-rpcresponse_ampinfrastructure-security
Publication policy:Why we publish these findings →

Related Posts