Four-Layer Security Review Methodology

▶ Watch (03:48)

Signal’s codebase is reviewed across four layers: design (what the spec says), intent (what engineers understood), implementation (what they wrote), and execution (how code behaves at runtime). Each layer surfaces different bugs and needs different techniques. Vulnerabilities also sort into four classes: language-specific (memory corruption), application-specific (SQL injection), logic-based, and product-specific. Signal’s server runs Java and Rust with almost no C++. The cross-platform library is Rust, which cuts the memory-corruption surface to near zero.

Signal’s Cryptographic Architecture: Profile Keys and the Double Ratchet

▶ Watch (07:49)

Profile data (names, pictures, status) is encrypted with an AES-256 GCM key generated on the client and never sent to the server. The key is shared only once a conversation starts, and only after the recipient replies. For message content, Signal uses elliptic-curve Diffie-Hellman pre-keys to agree a shared secret, then drives it through the double ratchet. Each message uses a unique derived key, deleted on delivery. When conversation direction changes, the ratchet resets, defeating both backward and post-compromise attacks.

Metadata Reduction: Sealed Sender

▶ Watch (14:21)

Signal envelopes include a “to” field (needed for routing) and a “from” field. In 2018, Signal introduced sealed sender (also called unidentified sender): the sender identity is placed inside the encrypted payload, so the server only sees the destination. Of four messaging apps with more than 10 million users El-sayed reviewed, Signal is the only one implementing both encrypted profiles and sealed sender. The profile key rotates only when a user blocks someone, which leaks that some account action occurred, even if the content stays hidden.

Plain Text Envelope Vulnerabilities on iOS and Android

▶ Watch (18:02)

Signal allows one type of plain-text envelope: the retry request, sent when a client cannot decrypt a message. Inside that envelope, the content protobuf supports 11 message types. iOS performed no type check on the plain-text path, so a malicious server could silently inject any of the 11 types into any thread.

“And this is the first vulnerability we have.” — Ibrahim El-sayed

Android added validation but omitted the data-message check. Its execution order processes the data message first regardless, so the injection still worked. Desktop exited each handler before reaching secondary blocks and was not affected.

Sync Message Authorization Bypass

▶ Watch (25:29)

Android’s sync handler accepted messages from any sender without checking the sender identity. There are 22 sync types (sent, read, edit, contact, configuration) and each works over the normal end-to-end encrypted path. Desktop and iOS both validated that sync messages came from the account itself. Android did not. El-sayed demonstrated in a live configuration sync exploit demo (29:07), toggling read receipts off on a target device in real time. Signal patched it the same day, September 2024. Whisperfish shipped the same bug at CVE score 8.5.

“This is zero click.” — Ibrahim El-sayed

Notable Quotes

This is known as backward secrecy. Ibrahim El-sayed · ▶ 12:08

And this is the first vulnerability we have. Ibrahim El-sayed · ▶ 19:05

This is zero click. Ibrahim El-sayed · ▶ 27:43

Key Takeaways

  • Signal encrypts profile data, image URLs, and message content with client-generated keys the server never sees.
  • iOS accepted all 11 message types via the plain-text fallback path; Android missed only the data-message check.
  • Android’s missing sender-identity check on sync messages enabled a zero-click injection attack, patched September 2024.