How it works
cant.chat is a room for two that exists only while you're in it. Here is what actually happens — in plain words first, then the exact details for anyone who wants to check our work.
1. You open a room
Your browser makes up two things: a room name like silent-fox-42 and a 32-byte random key. The key becomes the tail of your link, after the #:
cant.chat/#silent-fox-42.k3Yk3Yk3Y…
The part after # is special: browsers never send it to a server. Not to ours, not to anyone's. Our server only learns a fingerprint of the key (a hash), which it uses to connect the two of you — and from which the key cannot be recovered.
2. They knock, you compare four emoji
When the other person opens the link, both browsers make fresh, one-time key pairs and swap the public halves — encrypted with your link key, so the server only sees noise. From both halves each side derives four emoji. If you both see the same four, there is nobody in the middle: not the server, not someone who intercepted the link. Say them out loud and let them in.
3. Who sees what
The server's whole job is to pass sealed envelopes between two browsers. It keeps no logs and stores nothing: a room is a small object in memory that exists while someone is connected and is discarded afterwards. It counts nothing. Like any website host, Cloudflare sees connection metadata — your IP address, when you connected, how much data went through. It never sees content, because content is encrypted with a key it never receives.
Calls and files are different: they go straight between the two browsers whenever the network allows (WebRTC, encrypted with DTLS-SRTP). That is faster and keeps the server out entirely — but, like any direct connection, it shows the other person your IP address. If the site has a relay configured, “Hide my IP” in the room menu sends everything through the relay instead.
In Telegram. The bot @cantchatapp only shows buttons. A button opens this same site inside Telegram, so keys are made on your phone exactly as in a browser — and a note sealed there opens by its code here, and the other way round. Anything you type to the bot itself is deleted at once and never processed. One exception: the invite card you send by typing @cantchatapp in a chat. Its link is made by the server for a moment and not kept. The link alone does not unlock the conversation — the session key comes from a key exchange between the two browsers — and a substitution would show up as different emoji. If you want the key to exist nowhere but your phone, create the room with the button in the bot.
4. You burn it
Hold Burn, or just leave. Both browsers wipe their memory: messages, files, keys. There is no copy on the server to delete, because there never was one. The “Stored: 0 bytes” on the last screen isn't a promise — it's a description.
Notes: the one thing the server keeps
A note is for when the other person isn't online yet: write it, seal it with a code you choose, tell them the code. Because they'll open it later, the sealed note has to wait somewhere — and that somewhere is our server. It is the only thing the server ever stores, so here is exactly what that means: the note is encrypted in your browser with a key derived from the code; the server receives the encrypted block and a burn-by time (1 hour, 24 hours or 7 days), nothing else — not the code, not the key. The moment someone opens it, the server deletes it; if nobody does, it burns on schedule. We cannot read a note, restore one, or tell you who opened it.
The flip side: the note's safety is the code's safety. Someone who got hold of the encrypted block could try codes offline, so the form asks for at least 8 characters, shows a live strength meter while you type, and the slow hashing makes every guess cost. A short, obvious code is the one way to lose a note.
5. What we can't do
- Stop a screenshot. The other person's screen is theirs.
- Protect you if you hand the link to the wrong person. Whoever has the link can knock; the emoji tell you if someone is in between, not whether the person at the other end is who they claim.
- Hide that a conversation happened. Metadata (two addresses talked at this time) is visible to the host, as with any website.
For the technically minded
Everything below is implemented with the browser's built-in WebCrypto only; there are no third-party libraries. The code is small and readable: public/crypto.js, public/app.js, public/rtc.js, src/worker.js. Download the full source (zip) — exactly what runs on this site, server included. If you find a weakness, we'd like to hear about it — see the Report abuse page.
Keys
- Link key — 32 bytes from
crypto.getRandomValues, encoded base64url in the URL fragment. Never leaves the browser except inside the link you share. - Room ID —
SHA-256("cant.chat/room:" ‖ linkKey), first 20 bytes, hex. The only thing the server learns. - Wrap key —
HKDF-SHA256(linkKey, salt = 0³², info = "cant.chat/wrap/v1")→ AES-256-GCM. Encrypts the handshake (knock, public keys, admit) so the server cannot substitute keys. - Identity — per session, each browser generates an ephemeral ECDH P-256 key pair; the raw 65-byte public key is sent inside the wrapped handshake.
- Session key —
HKDF-SHA256(ECDH(shared), salt = linkKey, info = "cant.chat/session/v1")→ AES-256-GCM. Because the ECDH keys are ephemeral, a link that leaks later cannot decrypt a recorded conversation (forward secrecy against link disclosure). - Verification emoji —
SHA-256("cant.chat/verify:" ‖ linkKey ‖ pubA ‖ pubB)with the public keys sorted bytewise; the first four bytes index a 64-emoji table (24 bits). Equal emoji on both sides ⇒ both sides derived the session from the same two public keys. - Note —
noteKey = HKDF-SHA256(codeKey, 0³², "cant.chat/note/v1"),noteId = SHA-256("cant.chat/note:" ‖ codeKey)[0..20]. The client PUTs{ct, ttl}to/note/<id>; one Durable Object per id stores the sealed block and sets an alarm for expiry; the first POST returns the block and deletes it atomically. Same-site origin check and per-IP rate limits on both operations. - Room code (optional) — a passphrase the host chooses (minimum 6 characters, with a live strength meter);
PBKDF2-SHA256(code, salt = "cant.chat/code/v1", 200 000 iterations)→ a temporary key for a one-time “lobby” room through which the real 256-bit link key is handed over, wrapped as above. The code expires in 10 minutes and is single-use. Its strength is the strength of the passphrase: a guessable code can be brute-forced offline by anyone who observed the lobby traffic, which is why the UI shows the strength and the link remains the recommended path.
Messages
- Every application message is JSON, sealed with AES-256-GCM under the session key with a fresh 96-bit random IV. The plaintext carries the sender role and a strictly increasing counter; the receiver rejects replays, reordering and reflections of its own messages.
- WebRTC signalling (offers, answers, ICE candidates) travels inside these sealed messages, so the server cannot inject itself into a call. Media is DTLS-SRTP, keys negotiated between the two browsers.
- Files are split into chunks and sent over a WebRTC data channel (encrypted by DTLS) or, as a fallback, inside sealed messages via the server. Filenames and MIME types are sanitised on receipt; only known image/video/audio types are rendered inline, everything else is offered as a download.
Server
- A Cloudflare Worker with one Durable Object per room ID; two WebSockets maximum; no storage API is used for rooms. Reconnection is authorised by a per-connection random token so a third party with the link cannot displace a participant.
- TURN credentials are issued only inside a room that already has two participants, rate-limited per connection; new WebSocket connections are rate-limited per IP.
- Strict CSP (
default-src 'none', no inline scripts), HSTS, no referrer, no cookies, no third-party resources.
Known limits
- Metadata (IP, timing, sizes, room ID) is visible to the host; traffic analysis is possible in principle.
- The link is the trust anchor. The emoji check detects a man-in-the-middle, not an impostor who legitimately received the link.
- There is no identity, so there is no way to re-verify the same person across rooms — by design.
- Browser code is loaded from the server on every visit; a compromised server could serve malicious code. Open source and reproducible deploys mitigate but do not eliminate this; this is true of every web-based messenger.
Så fungerar det
cant.chat är ett rum för två som bara finns medan ni är i det. Här är vad som faktiskt händer — först med enkla ord, sedan de exakta detaljerna för den som vill granska vårt arbete.
1. Du öppnar ett rum
Din webbläsare hittar på två saker: ett rumsnamn som silent-fox-42 och en slumpmässig nyckel på 32 byte. Nyckeln blir slutet av din länk, efter #:
cant.chat/#silent-fox-42.k3Yk3Yk3Y…
Delen efter # är speciell: webbläsare skickar den aldrig till någon server. Inte till vår, inte till någon annans. Vår server får bara veta ett fingeravtryck av nyckeln (en hash), som den använder för att koppla ihop er två — och ur vilket nyckeln inte kan återskapas.
2. De knackar, ni jämför fyra emojier
När den andra personen öppnar länken skapar båda webbläsarna nya engångsnyckelpar och byter de publika halvorna — krypterade med din länknyckel, så servern ser bara brus. Ur båda halvorna härleder varje sida fyra emojier. Ser ni båda samma fyra finns ingen emellan: inte servern, inte någon som snappat upp länken. Säg dem högt och släpp in.
3. Vem ser vad
Serverns hela uppgift är att skicka förseglade kuvert mellan två webbläsare. Den för inga loggar och lagrar inget: ett rum är ett litet objekt i arbetsminnet som finns medan någon är ansluten och kastas därefter. Den räknar ingenting. Som varje webbvärd ser Cloudflare anslutningsmetadata — din IP-adress, när du anslöt, hur mycket data som passerade. Den ser aldrig innehåll, eftersom innehållet är krypterat med en nyckel den aldrig får.
Samtal och filer är annorlunda: de går direkt mellan de två webbläsarna så fort nätverket tillåter (WebRTC, krypterat med DTLS-SRTP). Det är snabbare och håller servern helt utanför — men som varje direktanslutning visar det motparten din IP-adress. Har sajten ett relä konfigurerat skickar ”Dölj min IP” i rumsmenyn allt via reläet i stället.
I Telegram. Boten @cantchatapp visar bara knappar. En knapp öppnar samma sajt inne i Telegram, så nycklarna skapas i din telefon precis som i en webbläsare — och en lapp som förseglats där öppnas med sin kod här, och tvärtom. Allt du skriver till själva boten raderas direkt och behandlas aldrig. Ett undantag: inbjudningskortet du skickar genom att skriva @cantchatapp i en chatt. Dess länk skapas av servern för ett ögonblick och sparas inte. Länken ensam låser inte upp samtalet — sessionsnyckeln kommer från ett nyckelutbyte mellan de två webbläsarna — och ett utbyte skulle synas som olika emoji. Vill du att nyckeln bara ska finnas i din telefon, skapa rummet med knappen i boten.
4. Du bränner det
Håll Bränn, eller bara gå. Båda webbläsarna rensar sitt minne: meddelanden, filer, nycklar. Det finns ingen kopia på servern att radera, för det fanns aldrig någon. ”Lagrat: 0 byte” på sista skärmen är inget löfte — det är en beskrivning.
Lappar: det enda servern behåller
En lapp är för när den andra personen inte är online än: skriv den, försegla den med en kod du väljer, säg koden. Eftersom den öppnas senare måste den förseglade lappen vänta någonstans — och det någonstans är vår server. Det är det enda servern någonsin lagrar, så här är exakt vad det innebär: lappen krypteras i din webbläsare med en nyckel härledd ur koden; servern får det krypterade blocket och en brinntid (1 timme, 24 timmar eller 7 dagar), inget annat — inte koden, inte nyckeln. I samma stund någon öppnar den raderar servern den; gör ingen det brinner den enligt schema. Vi kan inte läsa en lapp, återställa en eller berätta vem som öppnade den.
Baksidan: lappens säkerhet är kodens säkerhet. Den som kommit över det krypterade blocket kan prova koder offline, så formuläret kräver minst 8 tecken, visar en styrkemätare medan du skriver, och den långsamma hashningen gör varje gissning dyr. En kort, uppenbar kod är det enda sättet att förlora en lapp.
5. Vad vi inte kan göra
- Stoppa en skärmbild. Den andra personens skärm är deras.
- Skydda dig om du ger länken till fel person. Den som har länken kan knacka; emojierna säger om någon står emellan, inte om personen i andra änden är den de utger sig för.
- Dölja att ett samtal ägt rum. Metadata (två adresser pratade vid den här tiden) är synlig för värden, som på varje webbplats.
För den tekniskt intresserade
Allt nedan är byggt enbart med webbläsarens inbyggda WebCrypto; inga tredjepartsbibliotek. Koden är liten och läsbar: public/crypto.js, public/app.js, public/rtc.js, src/worker.js. Ladda ner hela källkoden (zip) — exakt det som körs på sajten, servern inräknad. Hittar du en svaghet vill vi gärna höra om det — se sidan Anmäl missbruk.
Nycklar
- Länknyckel — 32 byte från
crypto.getRandomValues, base64url-kodad i URL-fragmentet. Lämnar aldrig webbläsaren utom i länken du delar. - Rums-ID —
SHA-256("cant.chat/room:" ‖ linkKey), första 20 byte, hex. Det enda servern får veta. - Omslagsnyckel —
HKDF-SHA256(linkKey, salt = 0³², info = "cant.chat/wrap/v1")→ AES-256-GCM. Krypterar handskakningen (knack, publika nycklar, insläpp) så att servern inte kan byta ut nycklar. - Identitet — per session skapar varje webbläsare ett tillfälligt ECDH P-256-nyckelpar; den råa publika nyckeln på 65 byte skickas inuti den omslutna handskakningen.
- Sessionsnyckel —
HKDF-SHA256(ECDH(shared), salt = linkKey, info = "cant.chat/session/v1")→ AES-256-GCM. Eftersom ECDH-nycklarna är tillfälliga kan en länk som läcker senare inte dekryptera ett inspelat samtal (forward secrecy mot länkläckage). - Verifieringsemojier —
SHA-256("cant.chat/verify:" ‖ linkKey ‖ pubA ‖ pubB)med de publika nycklarna sorterade bytevis; de första fyra byten indexerar en tabell med 64 emojier (24 bitar). Samma emojier på båda sidor ⇒ båda sidor härledde sessionen ur samma två publika nycklar. - Lapp —
noteKey = HKDF-SHA256(codeKey, 0³², "cant.chat/note/v1"),noteId = SHA-256("cant.chat/note:" ‖ codeKey)[0..20]. Klienten PUT:ar{ct, ttl}till/note/<id>; ett Durable Object per id lagrar det förseglade blocket och sätter ett alarm för utgång; första POST returnerar blocket och raderar det atomärt. Same-site-kontroll av origin och hastighetsbegränsning per IP för båda operationerna. - Rumskod (valfri) — en lösenfras som värden väljer (minst 6 tecken, med styrkemätare);
PBKDF2-SHA256(code, salt = "cant.chat/code/v1", 200 000 iterationer)→ en tillfällig nyckel för ett engångs-”lobbyrum” genom vilket den riktiga 256-bitarsnyckeln lämnas över, omsluten som ovan. Koden går ut efter 10 minuter och kan bara användas en gång. Dess styrka är lösenfrasens styrka: en gissningsbar kod kan knäckas offline av den som sett lobbytrafiken, därför visar gränssnittet styrkan och länken förblir den rekommenderade vägen.
Meddelanden
- Varje applikationsmeddelande är JSON, förseglat med AES-256-GCM under sessionsnyckeln med en ny slumpmässig 96-bitars IV. Klartexten bär avsändarens roll och en strikt stigande räknare; mottagaren avvisar återuppspelning, omordning och reflektioner av sina egna meddelanden.
- WebRTC-signalering (offers, answers, ICE-kandidater) färdas inuti dessa förseglade meddelanden, så servern kan inte skjuta in sig i ett samtal. Media är DTLS-SRTP med nycklar förhandlade mellan de två webbläsarna.
- Filer delas i bitar och skickas över en WebRTC-datakanal (krypterad av DTLS) eller, som reserv, inuti förseglade meddelanden via servern. Filnamn och MIME-typer saneras vid mottagning; bara kända bild-, video- och ljudtyper visas inline, allt annat erbjuds som nedladdning.
Server
- En Cloudflare Worker med ett Durable Object per rums-ID; högst två WebSockets; inget lagrings-API används för rum. Återanslutning auktoriseras med en slumpmässig token per anslutning, så att en tredje part med länken inte kan tränga undan en deltagare.
- TURN-uppgifter utfärdas bara i ett rum som redan har två deltagare, hastighetsbegränsat per anslutning; nya WebSocket-anslutningar begränsas per IP.
- Strikt CSP (
default-src 'none', inga inline-skript), HSTS, ingen referrer, inga kakor, inga tredjepartsresurser.
Kända begränsningar
- Metadata (IP, tidpunkter, storlekar, rums-ID) är synlig för värden; trafikanalys är i princip möjlig.
- Länken är förtroendeankaret. Emojikontrollen upptäcker en man-in-the-middle, inte en bedragare som legitimt fått länken.
- Det finns ingen identitet, så det går inte att verifiera samma person på nytt mellan rum — avsiktligt.
- Webbläsarkoden laddas från servern vid varje besök; en komprometterad server skulle kunna skicka skadlig kod. Öppen källkod och reproducerbara deployer mildrar men tar inte bort detta; det gäller varje webbaserad meddelandetjänst.
Как это устроено
cant.chat — комната на двоих, которая существует, только пока вы в ней. Вот что происходит на самом деле: сначала простыми словами, потом точные детали для тех, кто хочет проверить.
1. Ты открываешь комнату
Браузер придумывает две вещи: имя комнаты вроде silent-fox-42 и случайный ключ длиной 32 байта. Ключ становится хвостом ссылки, после #:
cant.chat/#silent-fox-42.k3Yk3Yk3Y…
Часть после # особенная: браузеры никогда не отправляют её серверам. Ни нашему, ни чьему-либо. Наш сервер узнаёт только отпечаток ключа (хеш), по которому сводит вас двоих, — восстановить из него ключ нельзя.
2. Собеседник стучится, вы сверяете четыре эмодзи
Когда второй человек открывает ссылку, оба браузера создают свежие одноразовые пары ключей и обмениваются открытыми половинками — зашифрованными ключом из ссылки, так что сервер видит шум. Из обеих половинок каждая сторона вычисляет четыре эмодзи. Если у вас они одинаковые — между вами никого нет: ни сервера, ни того, кто перехватил ссылку. Назовите их вслух и впускайте.
3. Кто что видит
Вся работа сервера — передавать запечатанные конверты между двумя браузерами. Он не ведёт логов и ничего не хранит: комната — маленький объект в памяти, который существует, пока кто-то подключён, и после этого выбрасывается. Он ничего не считает. Как любой хостинг, Cloudflare видит метаданные соединения: твой IP-адрес, время, объём данных. Содержимое он не видит никогда, потому что оно зашифровано ключом, которого у него нет.
Звонки и файлы устроены иначе: они идут напрямую между браузерами, когда сеть это позволяет (WebRTC, шифрование DTLS-SRTP). Так быстрее, и сервер вообще не участвует — но, как любое прямое соединение, это показывает собеседнику твой IP-адрес. Если на сайте настроен релей, пункт «Скрыть мой IP» в меню комнаты пустит всё через него.
В Telegram. Бот @cantchatapp только показывает кнопки. Кнопка открывает этот же сайт внутри Telegram, поэтому ключи создаются у тебя в телефоне точно так же, как в браузере, — и записка, запечатанная там, открывается по коду здесь, и наоборот. Всё, что ты пишешь самому боту, сразу удаляется и никак не обрабатывается. Одно исключение — карточка-приглашение, которую отправляют, набрав @cantchatapp в чате. Её ссылку на миг создаёт сервер и не сохраняет. Одна ссылка не открывает разговор — ключ сессии получается из обмена ключами между двумя браузерами, — а подмену выдали бы разные эмодзи. Если хочешь, чтобы ключ не существовал нигде, кроме твоего телефона, создавай комнату кнопкой в боте.
4. Ты сжигаешь
Зажми «Сжечь» или просто выйди. Оба браузера стирают память: сообщения, файлы, ключи. На сервере нечего удалять, потому что копии там никогда не было. «Сохранено: 0 байт» на последнем экране — не обещание, а описание.
Записки: единственное, что сервер хранит
Записка — для случая, когда собеседник ещё не в сети: напиши, запечатай кодом, который придумал сам, назови код. Раз откроют позже, запечатанная записка должна где-то ждать — и это «где-то» наш сервер. Это единственное, что он вообще хранит, поэтому вот ровно что это значит: записка шифруется в твоём браузере ключом, выведенным из кода; сервер получает зашифрованный блок и время сгорания (1 час, 24 часа или 7 дней) — и больше ничего: ни кода, ни ключа. В момент открытия сервер удаляет блок; если никто не открыл — он сгорает по сроку. Мы не можем ни прочитать записку, ни восстановить, ни сказать, кто её открыл.
Обратная сторона: безопасность записки равна безопасности кода. Тот, кто добыл зашифрованный блок, может подбирать коды оффлайн, поэтому форма просит минимум 8 знаков, показывает силу кода прямо при вводе, а медленное хеширование делает каждую попытку дорогой. Короткий очевидный код — единственный способ потерять записку.
5. Чего мы не можем
- Запретить скриншот. Экран собеседника — его экран.
- Защитить, если ты отдал ссылку не тому. Кто имеет ссылку, тот может постучаться; эмодзи показывают, нет ли кого между вами, а не то, что на том конце именно тот, за кого себя выдаёт.
- Скрыть сам факт разговора. Метаданные (два адреса общались в такое-то время) видны хостингу, как у любого сайта.
Для технически подкованных
Всё ниже реализовано только встроенным в браузер WebCrypto, без сторонних библиотек. Код небольшой и читаемый: public/crypto.js, public/app.js, public/rtc.js, src/worker.js. Скачать весь исходный код (zip) — ровно то, что работает на сайте, включая сервер. Нашли слабое место — напишите, контакт на странице «Сообщить о нарушении».
Ключи
- Ключ ссылки — 32 байта из
crypto.getRandomValues, base64url во фрагменте URL. Покидает браузер только внутри ссылки, которую ты отправляешь сам. - ID комнаты —
SHA-256("cant.chat/room:" ‖ linkKey), первые 20 байт в hex. Единственное, что узнаёт сервер. - Ключ обёртки —
HKDF-SHA256(linkKey, salt = 0³², info = "cant.chat/wrap/v1")→ AES-256-GCM. Шифрует рукопожатие (стук, открытые ключи, «впустить»), чтобы сервер не мог подменить ключи. - Личность — на сессию каждый браузер создаёт эфемерную пару ECDH P-256; открытый ключ (65 байт raw) передаётся внутри обёрнутого рукопожатия.
- Ключ сессии —
HKDF-SHA256(ECDH(shared), salt = linkKey, info = "cant.chat/session/v1")→ AES-256-GCM. Ключи ECDH одноразовые, поэтому ссылка, утёкшая позже, не расшифрует записанный разговор. - Эмодзи сверки —
SHA-256("cant.chat/verify:" ‖ linkKey ‖ pubA ‖ pubB), открытые ключи отсортированы побайтно; первые четыре байта индексируют таблицу из 64 эмодзи (24 бита). Одинаковые эмодзи ⇒ обе стороны вывели сессию из одних и тех же двух открытых ключей. - Записка —
noteKey = HKDF-SHA256(codeKey, 0³², "cant.chat/note/v1"),noteId = SHA-256("cant.chat/note:" ‖ codeKey)[0..20]. Клиент кладёт{ct, ttl}методом PUT в/note/<id>; один Durable Object на id хранит запечатанный блок и ставит будильник на срок; первый POST отдаёт блок и удаляет его атомарно. Проверка same-site origin и лимиты по IP на обе операции. - Код комнаты (по желанию) — фраза, которую придумывает хозяин (минимум 6 знаков, с живым индикатором силы);
PBKDF2-SHA256(код, salt = "cant.chat/code/v1", 200 000 итераций)→ временный ключ одноразовой «прихожей», через которую передаётся настоящий 256-битный ключ ссылки, завёрнутый как выше. Код живёт 10 минут и работает один раз. Его стойкость равна стойкости фразы: угадываемый код можно перебрать оффлайн, наблюдая трафик прихожей, — поэтому интерфейс показывает силу кода, а ссылка остаётся рекомендуемым путём.
Сообщения
- Каждое сообщение приложения — JSON, запечатанный AES-256-GCM ключом сессии со свежим случайным IV 96 бит. Внутри — роль отправителя и строго растущий счётчик; получатель отбрасывает повторы, перестановки и отражения своих же сообщений.
- Сигналинг WebRTC (offer, answer, ICE-кандидаты) идёт внутри этих запечатанных сообщений, поэтому сервер не может встроиться в звонок. Медиа — DTLS-SRTP, ключи согласуют сами браузеры.
- Файлы режутся на куски и идут по каналу данных WebRTC (шифрование DTLS) или, как запасной путь, внутри запечатанных сообщений через сервер. Имена файлов и MIME-типы очищаются при приёме; встраиваются только известные типы картинок/видео/аудио, остальное — только скачать.
Сервер
- Cloudflare Worker, один Durable Object на ID комнаты; максимум два WebSocket; API хранилища для комнат не используется. Переподключение подтверждается случайным токеном соединения, поэтому третий со ссылкой не может вытеснить участника.
- Доступы TURN выдаются только в комнате, где уже двое, с лимитом на соединение; новые WebSocket-подключения ограничены по IP.
- Строгая CSP (
default-src 'none', без inline-скриптов), HSTS, no-referrer, без cookies и сторонних ресурсов.
Известные ограничения
- Метаданные (IP, время, размеры, ID комнаты) видны хостингу; анализ трафика в принципе возможен.
- Ссылка — якорь доверия. Сверка эмодзи ловит «человека посередине», а не самозванца, который законно получил ссылку.
- Личности нет, поэтому нельзя узнать того же человека в другой комнате — так задумано.
- Код браузера загружается с сервера при каждом визите; скомпрометированный сервер мог бы отдать вредоносный код. Открытый код и воспроизводимые деплои снижают риск, но не убирают его — это верно для любого веб-мессенджера.