Radicle vulnerability sends private repos in cleartext

Published: September 23, 2026

Radicle's handshake looks like WireGuard's. Everything after it is plaintext.

The allow list decides which peers may fetch a private repository from a seed. It says nothing about who can read that repository in transit.

On 23 September 2026, the Radicle vulnerability became public: two critical flaws in the network protocol that Radicle's nodes speak, disclosed together.

Every version released to date is affected, up to and including 1.10.3, and no fixed release exists yet, so the project is advising people to stop using private repositories over the network until the update lands.

The first flaw was reported by Konstantinos Maninakis on 24 June 2026, and the second by cryptocode on 12 August 2026. The disclosure is short, specific, and unusually direct about what users should do.

Illustration from the top of the Radicle disclosure page that announced the two network protocol flaws.

What the Radicle vulnerability breaks

The transport does not encrypt anything after the handshake. Gossip messages, repository identifiers, node addresses and the Git objects themselves cross the wire in the clear, private repositories included.

The handshake has a problem of its own. Peer authentication is broken, so a node can present a Node ID that is not its own.

Neither flaw is devastating alone, because impersonating an allow listed Node ID first requires knowing one, and the allow list is not public.

Together they are enough. An attacker on the path between two nodes sees the Node IDs at both ends, both normally on the allow list, reads whatever is exchanged while they watch, and can then use an identity they saw to fetch the entire repository on demand.

Public repositories fare better than private ones, since their contents are already visible to anyone who asks. Privacy was the whole point of the setting that failed.

Radicle's protocol guide describes the privacy model for private repositories as selective replication: a visibility flag, a list of allowed DIDs, and no claim of encryption at rest. The same guide states that once the handshake completes, all data exchanged between peers is fully encrypted and benefits from forward secrecy.

The code writes plaintext to the socket instead, the session keys the handshake derives are stored and never read, and the first byte after the handshake on a live connection to a production seed is the ASCII letter r that starts the word rad.

The Radicle vulnerability is not a broken cipher. It is a documented guarantee that the transport never implemented.

Banner illustration from the Radicle Protocol Guide, the page whose claim that peer traffic is fully encrypted the Radicle vulnerability contradicts.

That detail came from an independent reimplementation. A developer building a Radicle node for the browser rewrote the protocol in TypeScript and encrypted everything after the split, exactly as the Noise specification says, and no real node would talk to him.

Wireshark settled it. The other side was not encrypting anything, and the fault sat in a Rust crate that skips the authentication tag on an empty handshake payload, so handshake messages arrive smaller than the specification implies while the connection object moves on without touching the keys it derived.

There is no published byte level specification for what Radicle nodes say to each other, which is why a reimplementation caught this and a documentation review would not have. That gap is also the strongest argument for the migration the project now plans.

If you run a node, the second flaw is the one to sit with for a while, because the allow list was the privacy control rather than a second line behind encryption. Treating authentication and authorization as separate design problems is worth more here than any single patch.

What to do differently

1. Separate integrity, confidentiality, and identity. Radicle proved its objects with signatures while the same wire carried them readable, which is what happens when one control is asked to cover three properties at once; audit where your own stack leans on a signature or an access list to imply secrecy, and hold it against network security fundamentals.

2. Treat every private repository that synced as disclosed. Rotate any unencrypted credential, key, or token that lived in one, because copies that peers already fetched are beyond your reach; stopping your own node is a separate job, so list private repositories with rad ls --private --all and block each one with rad block <RID>, which sets an explicit policy instead of falling back to a default that may be permissive.

3. Plan the upgrade as a partition, not a patch. The protocol has no version negotiation and the fix changes the wire, so the release will be a major version and upgraded nodes will refuse to talk to older ones; the project is replacing its custom transport with iroh, a peer to peer stack built on open standards, and until that lands you should tunnel the hop between machines you control, using WireGuard, a VPN, or an SSH tunnel, rather than leaning on Tor as a blanket answer.

One configuration trap deserves naming. Radicle can route onion peers through a Tor SOCKS port, but that setting covers onion peers only, and the global node proxy option is not confidentiality, because the traffic leaves the exit in the clear. Nothing in the current release refuses clearnet peers.

The exposure is not fully reversible either. The project asks anyone who has transmitted a private repository to treat it as leaked, and to keep the local copy rather than delete it, since deleting from storage removes every fork of that repository that you hold.

Reading the whole problem as a trust model question, rather than a bug with a patch, is the frame that transfers, and the zero trust architecture guide covers the general version of that argument.

The assumption that broke

The old assumption was that a cryptographic handshake at the start of a connection secures the connection.

The new reality is that deriving session keys is not the same as using them, and an allow list is only as private as the handshake that guards it.

If a protocol cannot be fixed without splitting its own network in half, would you ship the break and strand the peers who do not upgrade, or keep both protocols alive until they migrate?