DEV Community

Vladislav.L
Vladislav.L

Posted on Originally published at shifrom.com

How SHIFROM carries its relay connection inside VLESS+REALITY

Originally published on shifrom.com.

SHIFROM is an open-source, end-to-end encrypted messenger designed on the assumption that the network between the device and the relay is hostile. The first app is for Android; iOS and web versions are planned. One of the routes the client can use to reach its relay is VLESS+REALITY, the outer protocol from the Xray-core project, embedded directly in the app. This note covers how that route is built, where it sits, what our one field run showed, and what it does not protect.

Scope, stated up front. SHIFROM is at Alpha 2 and has no supported public release yet (the Alpha 1 APK on GitHub is a historical test build). Its custom protocol composition (X3DH, Double Ratchet and Sealed Sender over libsodium primitives) has not had an independent audit. Everything below about how REALITY behaved on a real network rests on a single founder-run session: one budget Android handset, one mobile operator (MTS, mobile data, no VPN) in one Russian region, on 7 May 2026. That tells you what happened in that session, not that REALITY passes every DPI policy, every operator, or even the same operator today. Where this note describes design, it rests on our architecture decision records (ADR-019, ADR-020) and the code they describe, not on measurement. It deliberately says nothing about where or how the REALITY endpoint is deployed.


What REALITY is

REALITY makes a proxied connection look, to an on-path observer, like an ordinary TLS 1.3 session with a well-known website that we do not operate: a camouflage target. The client's handshake names that site. A client holding the endpoint's pre-shared parameters authenticates inside the handshake, using X25519 key agreement and standard TLS 1.3 record encryption, and gets a tunnel. Any connection that fails that check, including an active probe, is relayed byte for byte to the real camouflage site, so the prober receives that site's genuine certificate chain. A side effect worth stating: the camouflage site only ever sees connections that failed authentication, arriving from the endpoint's address. SHIFROM clients authenticate and never reach it.

What REALITY does not do matters as much. It does not hide that a connection exists, how long it lasts, or how many bytes it carries. It is not an anonymity system. It addresses filtering that keys on the appearance of the outer TLS flow, and it may not get past every DPI policy. Research on detecting REALITY exists; our research note from May 2026 recorded the prevailing field view that no scalable production attack was known, and treated that as something that can change.

Why a messenger needs more than one route

The companion note, When TLS stays open but accepted writes do not arrive, shows how a direct WebSocket path can fail on a mobile network without any error. ADR-019 records an earlier, separate problem: attempts to reach the relay through Tor with operator-run bridges stalled on Russian carrier networks, and the record attributes that to throttling of long TLS streams to datacenter address ranges. Those runs are not in our public field-test matrix, so we quote no figures from them here, and the companion note explains why we are cautious about naming any threshold.

ADR-019 also records the constraints that pointed to REALITY. The route had to work without the user installing a separate app, which excludes designs that depend on a standalone VPN or proxy client. And it should not rely on protocols the record describes as fingerprinted and blocked on Russian carriers, such as WireGuard and OpenVPN. REALITY does not try to look like nothing; it tries to look like something ordinary.

As the companion note concludes, no single transport is a foundation. REALITY is one route among several, and our research note says it should never become the only one.

Where REALITY sits: transports and privacy modes

The client talks to the relay through one transport interface with several routes behind it:

  • Direct WSS: the lowest-overhead route on ordinary networks.
  • WSS through embedded Xray VLESS+REALITY: for networks where direct WSS is disrupted by DPI.
  • WSS through a Tor v3 onion service: the strongest current network-origin hiding, scoped to text-only delivery.
  • REST send/poll: not a separate outer route but a delivery fallback for networks that pass HTTPS while degrading long-lived WebSocket frames. Moving between WebSocket and REST does not change message crypto.

The user does not pick a transport. They pick a privacy mode, and a transport manager walks the ordered chain that mode allows:

Mode Chain On exhaustion
Standard (default) direct WSS → REALITY → Tor user-visible error
Private REALITY → Tor user-visible error
Ghost Tor only fails closed; never downgrades

Private exists for users who treat any direct connection to a known relay endpoint as a correlation surface. Ghost never falls back to REALITY or direct WSS: if Tor cannot bootstrap, the app shows "Cannot reach relay" rather than silently using a less private route. Early research sketched wrapping Tor inside REALITY for this mode; shipped Ghost does not.

When REALITY is the active route, the relay sees the REALITY endpoint as the TCP origin, not the user's device. The endpoint does see the user's address, and the same operator runs both. That is why ADR-019 rejected an extra server-side Tor hop between endpoint and relay: it would add latency and failure modes while hiding information from a party that already runs both ends. Sealed Sender hides the sender identity inside the envelope in every mode; the mode changes IP-layer exposure, not application-layer cryptography.

The endpoint forwards only to the relay and drops every other destination, so it cannot serve as a general-purpose proxy. Its per-connection access log is disabled; its logs carry startup messages and unrecoverable errors only.

Running Xray inside an Android app

The client embeds Xray-core through libXray, the XTLS-maintained mobile wrapper, compiled with gomobile into a JNI library and loaded into SHIFROM's own process. A CI workflow in the repository builds it from unmodified upstream. Xray-core is MPL-2.0 and SHIFROM is AGPL-3.0-or-later; we do not modify Xray source, and ADR-019 notes that forking it would reopen the licence analysis.

The core runs inside the foreground messaging service the app already uses and exposes a SOCKS5 listener on the loopback interface; the relay client connects through that port. ADR-019 gives two reasons for running it in-process rather than as a separate binary. Aggressive memory managers on budget handsets tend to kill an orphaned child process independently, whereas an in-process core stops and restarts with the app and needs no second foreground notification. And a separate executable would need additional permission surface. The service moves through Off, Starting, Ready and Failed, mirroring the Tor service.

Before a route counts as usable, the manager starts it, waits for SOCKS readiness, then probes the relay's health endpoint through that port, proving the path end to end rather than a local listener. REALITY gets up to 30 seconds to prepare, because cold initialisation of the embedded core took about that long on our test handset (ADR-020); warm restarts return in milliseconds. The probe itself has a budget per route: 25 seconds for Direct (two 10-second attempts), 30 for REALITY and 90 for Tor. The app remembers a working route for 24 hours only when it is the mode's first choice; when a fallback wins, that memory is cleared, so the next walk starts from the first route again instead of settling on Tor. The chain is walked on cold start, service restart, mode switch and network change. Once connected, WebSocket degradation is handled by the REST fallback layer rather than by re-walking the chain.

The user sees the foreground notification: "Connecting via …", then "Online via …" naming the active route, or "Cannot reach relay (tried N)" with a retry if every route fails. Switching modes tears the connection down and walks the new chain.

This is an in-app proxy, not a device-wide VPN. With a VPN the user already runs, the relationship is competitive, not additive: per ADR-019, the VPN captures the app's traffic, and the REALITY route either fails or becomes redundant because the network observer now sees the VPN instead. A separate reconnaissance track on VPN compatibility, opened in June 2026, covers the direct and REST paths and does not cover REALITY.

What the field run showed, and what it did not

The public field-test matrix has one REALITY row. On 7 May 2026, on the budget handset over MTS mobile data in one Russian region, with no VPN and no separate proxy or Tor app, the REALITY outer transport was reachable end to end. That was the acceptance run for ADR-019, with a twin client on an emulator. Result: pass. Latency: not recorded. Repeats: none.

That is the whole public evidence. ADR-019 originally called this "production-validated"; a later amendment corrected the label to what it was, a founder-run acceptance run on one device, one carrier and one date. The matrix lists what is missing: one handset model, one region, Android version not recorded, no independent reproduction, and realtime WebSocket traffic inside REALITY on the Tele2 LTE path from the companion note designed but not field-tested. REALITY was not designed to address the stall described there, and we have not run an experiment isolating whether it does.

The privacy-mode test plan defines eight scenarios, several involving REALITY (for example, Standard mode on the Russian handset without a VPN: direct WSS expected to fail, REALITY to succeed). The public matrix records no runs of them, so we claim nothing from them.

What it does not do

  • It is not anonymity. The endpoint sees the user's address, and the same operator runs the relay.
  • The relay can still observe timing, sizes, authenticated sessions and delivery destinations. No route here eliminates timing and volume analysis, and an adversary watching both network egress and relay ingress at once is outside our threat model.
  • It does not help against blocking by address. Camouflage changes how a flow is classified, not whether an address is on a blocklist. That is true of any proxy, REALITY included.
  • It depends on a site we do not control. If the camouflage target changes or restricts access in a way that breaks the relaying, probes stop seeing a genuine site and the endpoint can be reclassified.
  • It carries TCP. UDP-based realtime media was outside this stage's scope.
  • So far it is in the Android app only. iOS and web versions of SHIFROM are planned; how this route will work in them is not settled yet.
  • It does not touch end-to-end encryption. The endpoint sees only ciphertext envelopes; its compromise reveals no message plaintext. That holds only as far as the unaudited protocol composition holds.

What is next

The gaps above set the work: repeat REALITY runs, other operators and regions, and realtime WebSocket traffic inside REALITY on the Tele2 LTE path, each recorded as a matrix row with its conditions, failures included. An iOS build of the embedded core is tracked separately. Our research note recommends an external review of the MPL-2.0/AGPL aggregation before Beta. None of these has a date.


SHIFROM is open source (AGPL-3.0-or-later). Architecture decisions, the threat model, the field-test matrix and known issues are public. If you work on transports for hostile networks, or want to find holes in ours, the code and design docs are at github.com/LiudvigVladislav/SHIFROM, and the project lives at shifrom.com.

Top comments (0)