Three practical attacks on the Session messenger
How a one-way key check and a missing message counter let a malicious server node, or simply the person you are chatting with, impersonate, reorder, drop and replay messages.
In short
- Session’s deployed protocol lets the person starting a chat verify the other side’s key, but not the other way round. A malicious server node can use this to impersonate a new contact.
- Messages are ordered by a timestamp the sender chooses, with no counter behind it. Any chat partner can backdate a message so it appears before your reply.
- Without counters, a malicious server node can also drop messages without a trace, and replay them by exploiting how deduplication trusts server-computed hashes.
Why look at Session?
Session is a decentralized, end-to-end encrypted messenger that needs no phone number or email address to sign up. It is often recommended to people who need privacy most, such as activists and journalists, and it has been downloaded more than a million times on Google Play alone.
It began as a fork of Signal, whose protocol is among the most heavily analyzed in cryptography. In late 2020, Session replaced it with a design of its own, which we call Session Protocol V1, arguing that Signal’s assumptions fit a centralized server, not Session’s network of independently operated nodes. A 2021 audit by Quarkslab looked at the application, but the migration happened near the end of that audit, so the deployed design was only partly covered.
A custom protocol running on a permissionless network is exactly where guarantees that held in a centralized setting can quietly disappear. So instead of starting from the whitepaper, we read the code that actually ships: the iOS client, the libsession-util cryptographic library and the storage server.
How a Session message travels
Every user has two long-term key pairs: an Ed25519 key for signing and an X25519 key for key agreement. To message Bob, Alice first needs Bob’s public key, which she gets out of band by typing his Account ID or scanning his QR code. Note the asymmetry already: Alice learns Bob’s key, but Bob learns nothing about Alice’s.
For each message, Alice creates a fresh ephemeral key pair, derives a key with Bob’s long-term key, signs the message with her identity key, and encrypts it with NaCl’s crypto_box construction (XSalsa20-Poly1305):
Two timestamps matter later. The inner timestamp tells Bob’s client where to place the message in the conversation. The outer timestamp lets server nodes expire old messages and reject replays.
There is no central server. Each user’s public key maps to a swarm, a small group of storage nodes. Alice sends the packet through onion routing to one node in Bob’s swarm, the entry node, which checks the signature and timestamp window, shares the message with the rest of the swarm, and stores it under a hash. Bob later polls a random node in his swarm, sending the hash of the last message he received, and gets back everything newer along with each message’s hash. His client uses those hashes to skip duplicates.
Who is the attacker?
Session assumes neither clients nor servers are fully trusted, so we considered three adversaries.
- Malicious server node. Anyone can run a storage node by staking 25,000 SESH, roughly 2,700 USD at late-2025 prices. Such a node looks honest to users but can drop, alter or replay what passes through it.
- Malicious insider. A normal participant in a 1-to-1 or group chat. All it takes is a Session account and a conversation with the victim.
- Malicious group administrator. An insider who created a closed group and may also collude with, or run, a server node.
Against these, we checked the integrity goal stated in Session’s own whitepaper, the standard notions of confidentiality and authentication, and two properties a secure messenger should have: public key authenticity in both directions, and message ordering that is cryptographically protected rather than based only on what the sender claims.
Flaw 1: key authentication only goes one way
Alice verified Bob’s key out of band. Bob, receiving a first message from someone new, has nothing to check the sender’s key against. Signal and WhatsApp also trust a key on first use, but there the server is run by a single operator. In Session, the node that relays this first message can be anyone who paid the stake.
That gives the impersonation attack. Suppose Eve runs a node in Bob’s swarm and happens to be the entry node when Alice first writes to Bob.
How realistic is it?
In November 2025 the network had 1,596 active nodes in 274 swarms, about 5.8 nodes per swarm. Nodes cannot pick their swarm, so one attacker node lands in a given user’s swarm with probability about 1/1,596, and is then the entry node for a first message about 1 time in 5.8. That is small for one chosen victim, but an attacker does not need one chosen victim. Against a whole organization, or simply anyone, the odds add up, and every additional 2,700 USD node raises them linearly.
Session’s defenses are a separate inbox for message requests, and a key fingerprint that users can compare manually. The fingerprint is a 32-byte hex string, a format that user studies show people are poor at comparing. Worse, accounts can use any key pair, so an attacker can mine a key whose fingerprint matches the victim’s at the start and end. Matching 24 bits at each end is a 248 search, and an attacker with a whole swarm of roughly 212 users to choose from brings that to about 236, which is easy on commodity hardware.
Flaw 2: no counter behind the message order
The second flaw underlies the other two attacks. Session binds no message to a sequence number or ratchet state. Order comes entirely from the inner timestamp, and that timestamp is set by the sender. It is signed, but signing only proves the sender chose it, not that it is true. Server nodes check the outer timestamp, not the inner one, and clients enforce no strict window.
Attack 2: timestamp forgery by a chat partner
This attack needs no server at all. Any participant in a 1-to-1 or group chat can backdate or postdate their own messages. Picture a negotiation:
In our testbed, the attacker even restores a consistent view on their own device by clearing local state and logging in again, so both sides show the same, false, history. The attack also undercuts deniability. Session signs messages with long-term keys and tries to compensate by discarding signatures after verification, but an insider can simply keep them. The forged conversation then comes with signatures that look like proof.
Attack 3: dropping and replaying messages
A malicious node in the recipient’s swarm gets two more capabilities from the missing counter.
- Dropping. If the sender picks the malicious node as the entry node, it can discard the message before sharing it with the swarm. Without sequence numbers, the recipient has no gap to notice. The sender sees silence and may read it as being ignored.
- Replaying. The node shares the original as usual, but also stores copies under forged hashes. Because the client deduplicates using hashes the server computed, a recipient who polls the malicious node accepts each copy as a new message.
Neither attack reveals message content, but both quietly desynchronize what each participant believes was said. In a group, a malicious administrator can make it targeted: by generating group keys until one maps to a swarm containing a colluding node, they can drop or replay specific members’ messages while everything looks like normal network behavior.
This replay is different from the one Jaeger and Kumar found in Session’s legacy group protocol (EUROCRYPT 2025), which relied on timestamps that were not signed. That issue was fixed in the newer GroupsV2 protocol. Ours works against GroupsV2 and 1-to-1 chats, because it comes from the missing counter, not from a missing signature.
Status of the replay attack. In its technical assessment in late April 2026, the Session team classified the replay attack as unexploitable, because an incidental database configuration on the storage server currently blocks it. That protection is a side effect, not a designed security boundary: the protocol’s intended duplicate detection is still bypassed, and the protection would no longer hold if that configuration changed.
Reproducing it
We did not attack the live network. The stagenet only covered blockchain functions, not messaging, so we built a fully local copy instead and published it as the paper’s artifact, which received the USENIX Artifact Available badge.
- A Docker Compose network with a mock blockchain daemon, five honest storage nodes, and one malicious node whose attack mode can be switched at runtime between drop, replay and impersonate.
- Three iOS clients forked from the official app, playing sender, receiver and attacker, with every change marked in the source.
- One command-line tool that brings the network up and runs each attack, for example
./scripts/poc attack mode replay.
Disclosure
| Date | What happened |
|---|---|
| Dec 2025 | First disclosure, covering the impersonation attack |
| Jan 2026 | Second attempt, before our domestic presentation at SCIS 2026 |
| Mar 2026 | Report covering all three attack classes; the Session team acknowledged receipt |
| Late Apr 2026 | Technical assessment from the Session team: most findings accepted; replay classified as unexploitable because of an incidental database configuration |
| Jul 2026 | Remediation in progress; full patches still pending |
How to fix it
Make key verification mutual and usable. Both users should verify each other, by scanning each other’s QR codes or comparing a short numeric code in person, like Signal’s safety numbers. Splitting a numeric fingerprint into blocks also makes the partial-match keys from mining far easier to spot than a 64-character hex string.
Bind messages to an ordered state. The principled fix is a ratchet, as in Signal, WhatsApp, Threema and Matrix: each message is tied to an evolving chain of keys, so reordering, replay and omission become detectable, and forward secrecy comes along. Session dropped ratcheting partly because of complexity, and its announced Protocol V2 aims at forward secrecy and post-quantum security, which is a natural place to bring it back.
Until then, two cheap measures help. Servers and clients can reject or flag messages whose timestamps fall outside a fixed window around delivery time, trading tolerance for clock skew against room for forgery. And clients can recompute each message’s hash themselves instead of trusting the server’s, which stops replays under forged hashes, the same fix our co-author Hayato Kimura and colleagues proposed for a similar binding flaw in Nostr.
What I took away
Every signature in these attacks verifies. Nothing is broken at the level of primitives. What fails is the glue around them: which key is checked against what, and what a signature actually promises. That glue is also what changes when a protocol designed for a central server moves onto a network where anyone can run the server. Trust on first use is a reasonable trade-off when one company runs the relay; it is a different bargain when the relay costs 2,700 USD to join.
It also confirmed for me that reading the shipped code is worth the effort. None of these issues appear in the whitepaper. They show up in how the client deduplicates, which timestamp the server checks, and who the entry node happens to be.
Concurrently with our work, Yu and Haines analyzed Session together with the Oxen blockchain it runs on, in a paper at EuroS&P. If you are interested in Session’s network layer, it is worth reading alongside ours.