The WireGuard kernel module does not preserve AllowedIPs entries for peers when duplicate prefixes are inserted. A server with multiple peers can lose routing information for earlier peers after a new peer is added with an overlapping AllowedIPs value, even though the on-disk configuration remains correct.
In the reported case, wg show displayed one peer with allowed ips: (none) while the other retained 10.100.0.0/24. The affected peer continued to complete handshakes and deliver inbound packets, yet outbound traffic failed after decryption, incrementing rx_frame_errors on the interface.
Root Cause in the AllowedIPs Trie
AllowedIPs are stored in a single struct allowedips trie belonging to the wg_device. Each peer holds only a list of back-references to trie nodes. When an exact match on both prefix and CIDR length occurs during insertion, the code executes:
- rcu_assign_pointer(node->peer, peer) — redirects the node to the new peer
- list_move_tail — removes the node from the previous peer’s allowedips_list
The operation returns success (0) with no warning, and neither wg nor wg-quick performs overlap checks.
Observed Symptoms and Affected Systems
The problem manifests differently depending on prefix length:
- Two peers with identical 10.100.0.0/24 — the first peer loses its entry
- One peer with 10.100.0.0/24 and another with 10.100.0.5/32 — both entries remain because lengths differ
Real-world reports include OpenWrt users adding mobile peers with 0.0.0.0/0, VyOS and OPNsense issues from 2020–2025, and Kubernetes clusters using Cilium or Calico where pod CIDRs are generated automatically.
Packet Handling and Diagnostics
Inbound packets from an orphaned peer are dropped after decryption with the message “Packet has unallowed src IP”, incrementing frame errors. Outbound packets to an address without a peer return ENOKEY (“Required key not available”) and increment tx_errors. Dynamic debug can surface the source-address message, but the overwrite itself produces no log entry.
The same trie-reassignment logic exists in wireguard-go, wireguard-nt, FreeBSD, and OpenBSD implementations, confirming the behavior is not Linux-specific.


