monero.loveA little love for the network.
← All news

Monero / Security

Monero Developers Propose New Defenses Against Network Eclipse Attacks

How Nyx and Moros isolate Monero nodes, why NAT is not enough, and what four proposed defenses change. Verified code, reviews, tests and release status.

An isolated navy node connects only to orange hostile peers, while a separate honest network surrounds it.

A Monero node can check every block correctly and still receive a misleading view of the network. If an attacker controls every peer it talks to, the attacker can withhold new blocks or transactions. This is an eclipse attack.

On November 8, developers proposed changes to how Monero stores peer addresses and chooses connections. The largest, PR #11707, combines changes to network diversity, peer-list storage and connection selection. It follows research into attacks called Nyx and Moros, which target nodes with outbound connections only.

All four PRs were open and unmerged at the November 8, 15:31 UTC review. The latest official release was Monero v0.18.5.4, published October 17. It does not contain these proposed changes. A successful build of a development branch is not a released security update.

Monero eclipse attacks and a node's view

Nodes exchange blocks, transactions and peer addresses through Monero's peer-to-peer network. Each node sees the network through a limited number of connections. That makes the selection of those connections a security decision.

Imagine a node with twelve apparently separate neighbors. They answer its requests and exchange messages normally, but one operator controls them all. That operator can delay new blocks and refuse to relay transactions outside the group. A connection count alone would not reveal the problem.

The daemon, monerod, still validates the data it receives. It applies the consensus rules even when all its neighbors are hostile. Those neighbors can withhold data, but isolation does not reveal the wallet's seed or let them sign for its funds. Monero's daemon documentation explains its validation role and separation from wallet keys.

For an operator, a stale view can mean delayed synchronization or transactions that peers never forward. A miner may work on an outdated chain tip. Other attacks can build on isolation, but an eclipse alone does not establish a successful double spend or a break in Monero's transaction cryptography. Those claims require evidence about the follow-on attack too.

Peer-list poisoning and connection selection

Nodes need an address book of possible neighbors. Monero's code distinguishes a white list, containing peers the node has checked for reachability, from a gray list, containing candidates learned through peer exchange. It also keeps anchor peers for reconnecting after a restart. Even a white-list peer can be hostile. Answering a network probe establishes reachability, not honesty.

A hostile server can answer a handshake correctly. If enough hostile addresses enter the lists, normal connection selection can begin choosing them more often. Peer-list poisoning means manipulating that supply of candidates. It does not require rewriting the blockchain or taking over the operating system of every node that passes an address along.

The problem can spread through otherwise honest nodes. A node may advertise a reachable address without knowing who controls it. Another node receives that address through routine peer discovery and later connects to it. Our peer and peer-discovery definition covers the distinction between a network endpoint and a trusted source.

In Rucknium's earlier analysis and PR #11527, connection replacement often drew from the gray list first. White-list selection favored recently seen entries. An attacker could fill the candidate lists and move controlled peers into the recently seen group. The new proposals change those selection rules as well as the storage rules.

NAT blocks incoming connections, not hostile replies

A home router commonly uses network address translation, or NAT, to let private devices make Internet connections through a public IP address. Without an appropriate mapping or forwarding rule, an outside peer cannot simply open a new connection to the node. The IETF's description of traditional NAT explains this distinction between internally initiated sessions and outside access.

The node still receives data over connections it opened. A hostile peer can answer requests and advertise more addresses through an established connection, even while the router blocks unsolicited incoming connections.

An outbound-only node must discover honest neighbors through its own connections, because they cannot connect into it. Opening ports would restore that incoming path, but would also admit connections from hostile peers. The selection problem would remain.

Nyx and Moros research at ACM CCS 2026

The ACM CCS 2026 accepted-paper list includes Are Unreachable Nodes Truly Safe? Fully Eclipsing Monero's P2P Network!, by Ruisheng Shi and eight coauthors. The authors' paper was first posted September 9 and revised October 25. Its two attacks target different stages of a node's life.

Nyx targets an already running node

Nyx poisons reachable nodes' peer lists. Ordinary peer exchange then carries hostile candidates to an unreachable target. The target's normal outbound-connection refresh gradually replaces honest neighbors. The attacker does not need an inbound connection to the victim or a forced restart.

Moros targets the first connections

Moros attacks bootstrapping. At startup, a node requests candidate addresses from seeds before it has established a peer history. Poisoned seed responses can steer those first connections toward the attacker. This targets the seed's advertised address list, not necessarily control of the seed server itself.

The experiments have a defined scope

The paper's evaluation used a 1,200-node emulation running v0.18.4.3 for Nyx, reporting full takeover at about 27 minutes. Moros used controlled targets on mainnet and reported initial takeover within eight seconds. The time series include brief honest reconnections. These results are not measurements of every current node or evidence of network-wide isolation.

The proposed defenses and their dependencies

The proposals overlap. PR #11706 includes the selection change from #11705. The #11707 series includes both. The IPv6 proposal #11700 takes a different approach to limiting stored addresses.

PR #11707: spread connections across network groups

An IP address identifies an endpoint, but different addresses can belong to the same network or operator. Prefix grouping treats some of those addresses as one group when choosing peers. A /16 IPv4 group shares the first 16 address bits. An IPv6 /32 shares the first 32 bits. Address prefixes provide an approximation of network diversity. They cannot establish who owns a server.

The proposal's connection-selection code broadens IPv4 grouping from /24 to /16. Native IPv6 candidates use /32, which was already present in the compared base. IPv4-mapped IPv6 addresses follow the IPv4 grouping rule.

The filter excludes groups already in use by outgoing connections, and the patch removes the fallback that retried without subnet deduplication. It ignores incoming connections when counting occupied outbound groups. Otherwise, someone connecting into a node could influence which networks it avoids when making its own connections.

These rules apply to automatic peer-list selection. Manually configured and special-purpose connections need separate analysis. A stricter filter can also leave fewer eligible candidates, especially when a syncing node requires a specific pruning stripe. That availability tradeoff matters alongside resistance to concentrated peers.

Peer connections concentrate in one network group on the left and spread across separate groups on the right.

Addresses in one network group provide less diversity than connections spread across separate groups.

Buckets limit how much space one source can occupy

The peer-list code in #11707 divides storage into bounded buckets. White-list placement uses the candidate's network group. Gray-list placement also accounts for the network group of the peer supplying the candidate. A local random key influences placement.

Think of an address book with separate compartments rather than one queue that any busy sender can fill. A flood from one source group can reach only a limited subset of gray buckets. It cannot simply displace every entry from other sources. Each group can still contribute more than one stored address.

The proposed configuration constants allow 256 white buckets with 16 entries each and 256 gray buckets with 32 entries each. The total capacity is 4,096 white entries and 8,192 gray entries. Actual occupancy can be lower when entries compete for the same buckets.

The series also moves successful inbound ping-back discoveries into the gray list. They enter the candidate pool instead of going straight into the white list. This addresses the route by which an inbound flood can repeatedly introduce fresh white-list entries.

When a white bucket is full, a bounded queue lets housekeeping check an older entry before replacing it. A peer that still responds can keep its place. The combined branch also includes earlier proposals #11681, #11682 and #11683, covering stale advertisements, repeated connection failures and replacement checks. Our November 6 node-operations brief covered these earlier proposals. The combined branch needs review as a whole because it changes how they interact.

PR #11705: stop favoring recently seen peers

The selection patch removes the recency-biased draw and associated sorting. It chooses randomly among eligible candidates and tries the white list before falling back to gray.

Older reachable peers remain eligible even during a burst of new arrivals. Uniform selection still favors an attacker who dominates the list, which is why changing the draw alone cannot replace controls on what enters the list.

PR #11706: make fallback less aggressive

Trying the white list first is only part of the decision. The refill loop controls how many connections come from gray after a white-list attempt fails.

The refill change tries anchors, then white-list peers up to the configured outbound count. If necessary, it takes one gray-list connection and returns to trying white. It removes the fixed 70 percent white-list threshold.

This prevents one unsuccessful white-list selection call from handing all remaining vacancies to the gray-list loop. It still permits discovery through gray candidates when known peers are unavailable.

PR #11700: cap IPv6 white-list entries per /64

IPv6 offers many addresses within one prefix. Counting each address as a separate host can let one address allocation occupy much more peer-list space than the number of independent operators would suggest.

The #11700 diff reuses public IPv6 /64 grouping when admitting a new white-list address. A new entry replaces another from that group. Its regression test starts with a list of IPv4 peers. After inserting many addresses from one IPv6 /64, it checks that only one of those IPv6 entries remains.

This storage cap differs from #11707's broader /32 grouping for outbound selection and its multi-entry buckets. The distinction matters when assessing whether two patches complement or conflict with each other.

Code review and upstream test results

The review comments identify cases that successful compilation alone cannot settle.

On #11707, Ap4sh questioned replacement ordering. When a known IP appears on a new port, the code removes the old white-list entry before confirming that the new bucket can admit its replacement. If the destination bucket is full and its older peer still responds, the list can lose the known endpoint. The reviewed head still contains that ordering. The reviewer has not approved the PR.

On #11700, Ap4sh asked about saved lists. Deduplicating new admissions does not necessarily clean up cached entries sharing a /64 when an existing installation loads its list. The reviewer requested a test using pre-populated state. Nahuhh also questioned the approach, pointing to the bucketing series instead. Neither comment is evidence of developer consensus.

GitHub reports the following check runs for the specified PR heads. We inspected those upstream results without rerunning the Monero test suite.

  • PR #11707 checks, head 5ab84db: 18 successful, including Ubuntu 24.04 tests. One comment-only review, no approval.
  • PR #11705 checks, head dc9715e: 16 successful. Docker and Windows MSYS2 failed. No submitted reviews.
  • PR #11706 checks, head 7048e16: 18 successful, including Ubuntu 24.04 tests. No submitted reviews.
  • PR #11700 checks, head d73f4d4: 18 successful, including Ubuntu 24.04 tests. Discussion comments, no formal review.

For #11705, the Windows failure annotation reports an HTTP 504. For Docker, the annotation gives only exit code 1. The cause needs investigation before either blaming the patch or dismissing the failure.

The combined series adds or adjusts tests for network grouping, bucket limits, flood resistance, stale entries, collision handling and loading saved gray peers. The peer-list tests at the reviewed head show those cases. Testing the entire series against the attacks would require network experiments beyond these unit tests.

Earlier simulations tested a different patch

Rucknium's #11527 simulation report compared an earlier release with a defense using a larger white list and changed selection. The simulation used a 10,000-entry limit, while that PR proposed 45,000 for mainnet. The reported patched target retained honest connections in that setup.

The #11707 changes need their own evaluation because they use a different storage and selection design. At the November 4 Research Lab meeting, developers discussed competing approaches and whether to split the work into smaller PRs. The discussion also distinguished subnet-concentrated attackers from attackers with more distributed address resources. A test's address distribution is part of its threat model.

Limits of address-based diversity

Address diversity remains an imperfect substitute for operator diversity. One operator can control infrastructure in different ranges, while unrelated operators can share a hosting network. Broader grouping can make concentration harder while excluding some legitimate candidates. Limiting bucket occupancy constrains how much space a source can use without identifying whether it is malicious.

A running node may have years of peer history. A new installation starts without that history, so white-list preference initially has little to work with. Bootstrap behavior, saved-state migration, pruning requirements and the treatment of manual peers all need review alongside the ordinary steady-state path.

The patch series changes daemon networking while leaving transaction cryptography and issuance rules unchanged. Tor and I2P routing also leave the problem of selecting independent peers. Our guide to Monero transaction relay over Tor and I2P covers the separate problem of network observations and routing.

What node operators can do now

Check the official releases rather than treating an open PR as an upgrade notice. The reviewed release, v0.18.5.4, includes other fixes. These four proposals had no announced release version at the cutoff.

For an existing node, inspect synchronization progress, connection direction and peer churn. The documented status, sync_info and print_cn commands help show what the daemon is doing. Compare its height and recent block hashes through independently obtained references when investigating a discrepancy. Ordinary outages, configuration errors and synchronization delays can produce symptoms that resemble isolation, so a slow node is not proof of an attack.

Do not respond by copying an unreviewed fixed peer list, deleting saved peer state or adding exclusive peers without understanding the consequences. Consult the monerod options reference before choosing priority or exclusive peers. Exclusive peers restrict the node's connections. Concentrating trust in a small hand-picked set can create its own dependency.

Wallet users connecting to a remote node depend on that node's network view as well as its responses. Our wallet connection guide explains the wallet/node boundary. Running your own node gives you control over validation and connections, but its peer discovery still needs to work.

Support Monero Love

Help keep the public nodes and packages running. Send any amount of XMR.

Scan with a Monero wallet to donate to Monero Love.89hGTKxRVA3AUeKAbCRBt5TMSzq3MQZooNNsezCpNFjp2oeJPRx8AJeGKA8ziHZNqab78f4Vr1ntxhPDxX5298nnGZjHkhm