iman Messenger security whitepaper: protocol, threat model and limits

Published by:
iman
Published:
Last updated:

Summary

Short answer: in iman Messenger only secret chats (one-to-one, in the web app and the Android app) are end-to-end encrypted. They use the Signal protocol (X3DH key agreement and the Double Ratchet) through existing libsignal-based libraries. Regular chats, groups, channels and most calls are encrypted in transit and at rest on our servers, but iman can technically read them. No independent security audit has been published yet.

  • End-to-end encrypted: messages and files in one-to-one secret chats. The server stores and relays ciphertext only.
  • Not end-to-end encrypted: regular chats, groups, channels, and calls outside secret chats. Secret-chat calls are frame-encrypted only when both sides negotiate it.
  • You can check that nobody swapped the keys: compare the 60-digit safety number with your contact.
  • The server still sees metadata such as who talks to whom, when, message sizes and IP addresses.
  • Status: no independent audit and no paid bug bounty yet. Reports are welcome at the security contact below.

Scope: what is and is not end-to-end encrypted

SurfaceEnd-to-end encrypted?What protects it
Messages in a one-to-one secret chatYesSignal-protocol sessions between the two devices. The server stores and relays ciphertext only and rejects plaintext bodies in secret chats.
Files and media in a secret chatYesEncrypted on the sender's device. The media key travels inside the end-to-end encrypted message, and the server accepts only opaque encrypted files in secret chats.
Regular one-to-one chatsNoTLS in transit, and sealed at rest with a key held by the iman server. iman can technically read them.
Groups and channelsNoSame as regular chats. Groups and channels are cloud chats; group sender keys are not used.
One-to-one calls in a secret chatOnly when negotiatedFrame-level encryption on top of DTLS-SRTP when both clients support it and the call key was exchanged. Otherwise the call is labelled transport only. See Calls.
All other callsNoDTLS-SRTP between hops. Operators of relay and media servers are not excluded from the media.
Push notificationsNot applicableSee Push notifications.

Features that need the server to read content, such as polls and live location, are not available in secret chats. Secret chats are available in the web app and the Android app. This document makes no claims about other clients.

Protocol and primitives

  • Key agreement: X3DH (Extended Triple Diffie-Hellman). Each device has an identity key, a signed prekey, a pool of one-time prekeys and a last-resort prekey.
  • Message encryption: the Double Ratchet, which gives forward secrecy and recovery after a key compromise for message keys.
  • Implementation: the web app uses the open-source @privacyresearch/libsignal-protocol-typescript library, a community TypeScript port. Android uses signal-protocol-java 2.8.1 (org.whispersystems). iman does not implement its own cipher for message content. The primitives are those of these libraries (Curve25519 and XEdDSA, AES-CBC with HMAC-SHA256 for message bodies, as documented by the libraries).
  • Wire format: in secret chats the server accepts only the algorithm tags signal-v1 (one device) and signal-v1-md (one envelope per recipient device). It rejects plaintext bodies, GIF and sticker references and polls there.
  • Prekey hygiene: the signed prekey is rotated about weekly, and a rotated-out private half is kept for 14 days so late first messages still decrypt, then deleted. One-time prekeys are topped up when the server reports a low pool.
  • Key registration proof: a new device or a replaced identity key must prove possession of the identity private key (an XEdDSA signature over a fixed context string, a timestamp within 5 minutes and a single-use nonce). This stops another account from registering a copied public bundle. The server enforces it once its enforcement date setting is active.

Threat model

Secret chats are designed to protect message and file content against:

  • anyone watching the network (TLS plus end-to-end encryption);
  • someone who obtains a copy of the iman database or a server backup;
  • an iman server that merely stores and relays messages, provided you have verified your contact's safety number.

They do not protect against:

  • a compromised, unlocked or malware-infected device, or a screenshot or copy made by the other participant;
  • a malicious server substituting keys before you verify the safety number (trust on first use);
  • altered client code: the web app is delivered by the iman server on each load, so a compromised server could ship modified JavaScript;
  • traffic analysis and metadata (see Metadata);
  • legal or other compulsion of the operator for anything stored in cloud chats.

Key verification: safety numbers and call codes

  • Safety number: a 60-digit Signal numeric fingerprint (version 2), computed locally on your device from both identity keys and both user ids (SHA-512 iterated 5,200 times). It is not computed by the server, so the server cannot fake it. Both sides see the same number.
  • Trust on first use, per device: the first key seen for a contact device is accepted. A new device of a contact is shown as a notice. If you have verified the contact, a new device you have not checked blocks sending until you review it. A changed identity key is surfaced and the app asks you to verify it.
  • Several devices: each device has its own safety number. The combined value for several keys is an iman-specific extension (per-key digests folded together with XOR) and has no reference test vector.
  • Call code: a 6-digit code derived from the DTLS fingerprints of the two call endpoints (algorithm iman-dtls-sha256-6d-v1). It is a one-in-a-million check with no commitment step, it is not ZRTP, and it says nothing about the frame-encryption key, which comes from the Signal channel.
  • There is no key transparency log. Verification is manual.

Metadata

Even in secret chats the server necessarily handles account identifiers, which conversation a message belongs to, membership, timestamps, message and file sizes, IP addresses, and device and push registration data. End-to-end encryption protects content, not this information. Privacy settings such as last seen control what other users see, not what the server sees.

Content of regular chats, groups and channels is stored on the server, sealed at rest (see Storage on devices, backups and account recovery).

Sealed sender: status and limits

  • What it does: for secret chats, a sealed message is stored without the sender's identity. The message row, the conversation's last-message sender, the sync log, the delivery retry queue and the payload sent to the recipient carry no sender id. The true sender can still delete for everyone by presenting an author proof, which the server stores only as a hash.
  • How it is delivered: when the peer's key allows it, the web app sends through an unauthenticated delivery endpoint using a per-conversation capability instead of a bearer token. If that route fails, the web app does not silently re-send the message in an authenticated way; you can choose to retry that way per message.
  • What it does not do: it is not network anonymity and does not hide the sender from the operator. The sender still made authenticated key requests just before, the IP address and timing are visible, and in a two-person chat the sender is the other member by elimination.
  • Verification scope: we verified this behaviour in the web client and the server code. Equal behaviour on Android is not claimed here.

Push notifications

  • Secret chats: the notification text is a fixed generic line (“You have a new message”). Identifiers of the chat and the sender are removed before the push is handed to the platform push provider, and no notification thread id is set.
  • Regular chats, groups and channels: a notification can carry the sender name and a text preview. These pass through the platform push services of Google and Apple.
  • On our servers the pending push text is sealed at rest and is cleared once the push is delivered.

Calls

  • Every call uses WebRTC with DTLS-SRTP. One-to-one calls can be peer-to-peer or go through a relay; calls through a media server (SFU) are decrypted there, so they are transport-encrypted only, not end-to-end.
  • Secret one-to-one calls can add frame-level end-to-end encryption: AES-256-GCM per media frame via Insertable Streams, with per-stream keys derived using HKDF-SHA256 from a call secret that the two clients exchange inside a Signal-encrypted message. The server never holds that key.
  • Honest labelling: the server reports frame encryption only when the chat is secret and every party declared support. The client shows an end-to-end label only when its own cipher is running and the call key arrived. Otherwise the call is labelled transport only.
  • Status: the web app implements this. On Android the frame-encryption path is behind a build flag (SECRET_CALL_FRAME_E2EE) that is off by default, so Android calls are transport-encrypted unless that build enables it.
  • Regular and group calls are not claimed to be end-to-end encrypted.

Storage on devices, backups and account recovery

  • On the web device: Signal keys, sessions and decrypted-message data in the browser's IndexedDB are sealed with AES-256-GCM under a non-extractable WebCrypto key. An optional PIN wraps the keys with PBKDF2-HMAC-SHA256 (600,000 iterations by default). Limit: code running in the same origin can use the key while the app is unlocked, and a compromised device defeats this protection.
  • No backup of secret chats: there is no server-side backup or key escrow for them. Secret chats exist only on the devices where they were created. If you lose all of them, the history is gone. Re-registering with the same phone number restores cloud chats, not secret chats.
  • Cloud chats on the server: message text and attachments are sealed at rest with authenticated encryption under a key ring held on the server side. This protects against a stolen disk or database copy, not against an operator who holds the keys.

Multiple devices

  • Each device has its own identity key and Signal device id. The sender encrypts separately for every device of the recipient (the signal-v1-md envelope).
  • Settings list the devices that can read your secret chats. Removing one stops it receiving messages and signs its sessions out.
  • Secret-chat history is not transferred to a new device.
  • When a verified contact adds a device you have not checked, sending is blocked until you compare that device's safety number.

Disappearing messages

In a secret chat either participant can set the chat's timer. Expired messages are physically removed from the server by a periodic sweep. A timer cannot force the other person's device to delete a copy, a screenshot or a forwarded message.

Known limits and gaps

  • Groups, channels and regular chats are not end-to-end encrypted.
  • Secret chats are one-to-one only and exist in the web and Android apps only.
  • Until you verify a safety number, a malicious server could substitute keys. There is no key transparency log.
  • Sealed sender is not network anonymity.
  • The web app trusts the code the server sends on each load.
  • Calls: end-to-end only for negotiated secret one-to-one calls; the Android path is off by default; the call code is a small check.
  • The multi-device safety number is a custom extension without reference vectors.
  • Message sizes, timing and the social graph are visible to the server.
  • The cryptography relies on third-party libraries whose own audits we do not control, and we have not published an independent audit of how iman uses them.

Audit, testing and bug bounty status

  • Independent third-party security audit: none published as of 2026-10-08.
  • External review of the cryptographic design: none published.
  • Internal work: automated tests cover the safety number, key trust, prekeys and sealed sender, and the messenger was reviewed internally on 2026-10-03. An internal review is not an independent audit; treat the claims in this document as self-reported.
  • Bug bounty: there is no paid bug bounty program at the moment.
  • If any of this changes, this section and the changelog will be updated.

Responsible disclosure

If you find a vulnerability, please write to the security contact below and include what you found, how to reproduce it and the affected platform. Please do not access other people's data, degrade the service or disclose the issue publicly before we have had a chance to respond. We do not offer a bounty and do not yet publish a response-time commitment. The machine-readable contact is in /.well-known/security.txt.

Security contact: privacy@iman.tj

How to verify a contact's safety number in an iman secret chat

Compare the 60-digit safety number with your contact to confirm that nobody swapped the encryption keys of your secret chat.

  1. 1. Open a secret chat

    Start or open a secret chat with your contact in the web app or the Android app. Secret chats are the end-to-end encrypted ones.

  2. 2. Open the safety number

    Open the chat's security details and choose Verify to see the safety number: 60 digits in groups of five.

  3. 3. Compare it on a separate channel

    Compare the number with the one on your contact's screen, in person or over a call where you recognise their voice. Do not use the same chat to compare it.

  4. 4. Mark it as verified only if it matches

    If the numbers are identical, mark the contact as verified. If they differ, do not verify: each device has its own number, so check you are comparing the device your contact is using, and treat a persistent mismatch as a possible interception.

  5. 5. Re-verify after a change notice

    If iman shows that the safety number changed or that your contact registered a new device, compare again before sending anything sensitive.

  6. 6. Optionally check the call code

    During a call, compare the 6-digit call code with your contact the same way. It checks the call connection, not the message keys.

Questions and answers

Is iman Messenger end-to-end encrypted?
Only secret chats are: one-to-one chats in the web and Android apps, using the Signal protocol. Regular chats, groups, channels and most calls are encrypted in transit and at rest on the server but are not end-to-end encrypted.
Can iman read my regular chats?
Technically yes. Regular chats, groups and channels are stored on the server, sealed at rest with a key the server side holds. Use a secret chat for conversations that must not be readable by iman.
Which encryption protocol does iman use for secret chats?
The Signal protocol: X3DH key agreement and the Double Ratchet, implemented by existing libsignal-based libraries rather than by custom ciphers.
Are group chats end-to-end encrypted?
No. Groups and channels are cloud chats and do not use group sender keys.
Do notifications reveal message content?
For secret chats the notification is a generic line with no chat or sender identifiers. For other chats it can include the sender name and a preview, which pass through Google or Apple push services.
Has iman been independently audited?
Not yet. No independent audit has been published and there is no paid bug bounty. The messenger has had internal review only.
How do I report a security vulnerability?
Write to the security contact on this page or use the address in /.well-known/security.txt. Include reproduction steps and the affected platform.

Changelog

  • : First publication. The document describes the behaviour of the iman client and server code as of this date.
  • : Internal-review fixes present in the code this document was written from: possession proof for key registration, a sealed-delivery capability that separates the recipient's secret from the sender's credential, no silent fallback from sealed to authenticated sending, and per-device trust on first use that blocks sending to a verified contact's unchecked new device.
  • : Internal security review of the messenger completed. This is not an independent audit.

Back to Securityiman MessengerPrivacy features