# BaleVPN tunnels IP traffic through a voice call, and tells you the operator can read it

> BaleVPN is a peer-to-peer VPN that carries IP traffic inside the voice-call infrastructure of Bale, an Iranian messaging app, so the link looks to Bale like a long call between two contacts. Its documentation is unusually honest about the cost of that: Bale runs the relay node, sees the social graph, and the project's own recommendation is to register on a throwaway number.

**kookoo1sabzy/BaleVPN** — P2P VPN Tunnel Over Bale Messaging System

- Repository: https://github.com/kookoo1sabzy/BaleVPN
- Stars: 401 · Forks: 85
- Language: Rust
- License: MIT
- Published: 2026-09-20 · Updated: 2026-09-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/kookoo1sabzy-balevpn

## A VPN that looks to the operator like a long voice call

The mechanism is unusual enough to state plainly. BaleVPN is a peer-to-peer VPN that tunnels IP traffic over the voice-call infrastructure of Bale, the national Iranian messaging app. One device runs as the server and provides internet, another runs as the client and consumes it, and to Bale's own servers the whole link looks like a long voice call between two contacts. Nothing about the signalling distinguishes it from a call.

The stated purpose is reachability rather than privacy. When one person has a working, uncensored connection and the other does not, the second can route traffic through the first with no extra server, no account, no payment, and no signup. The setup is two phones, or a phone plus a laptop on the server side, with the two accounts holding each other in their contact lists, and then a connection. The documented simplest start is two Android phones: install the APK on both, sign in with your Bale account inside the app, set one to Server and the other to Client.

Two framing details are worth carrying through the rest of this. The project states there is no commercial relationship with Bale, so there is nobody to ask about the arrangement. And the whole page is mirrored in Persian inside a right-to-left block, with a separate Persian Android setup guide next to the English one, which is what you would expect from a tool whose users are inside the network it is designed to route around.

## Bale is the relay node, and that is the entire privacy story

The encryption is real but it does not cover the party that matters. The LiveKit data channel is encrypted with DTLS, so the traffic is opaque to passive observers on the network and to ISP middleboxes sitting in the path. However, Bale's LiveKit server is the selective forwarding unit and the TURN node for the call, which means it has access to the plaintext of the data flowing through it. The project then spells out exactly what that buys the operator.

Bale can see who relays for whom. Every tunnel session is a voice call between two accounts, so the call records reveal the social graph: which account used which relay, when, and for how long. Bale can see which destinations you connect to, as IP address and port, plus the hostname embedded in the TLS SNI field of any HTTPS request you make through the tunnel. And Bale can read the contents of any traffic that is not itself end-to-end encrypted, so browsing only encrypted web sites leaves the payload opaque while plaintext HTTP, DNS, or FTP through the same tunnel is readable.

The framing the project offers is the useful part: treat this tunnel like a corporate VPN whose operator you do not fully trust. It is fine for IP-level reachability, which is the uncensoring case, and it is explicitly not adequate as an anonymity or end-to-end privacy layer. The advice that follows is to use TLS at the application level, including encrypted DNS, and treat the tunnel as transport rather than as protection.

## SOCKS5 mode adds a QUIC layer that protects against the wrong attacker

There is a second mode and a second, more elaborate warning attached to it, and the warning is the most valuable paragraph in the file because it describes a protection that looks stronger than it is. When you use SOCKS5 instead of a full VPN, the tunnel carries client-to-server traffic inside a QUIC channel that adds its own TLS 1.3 encryption on top of the LiveKit data channel. That layer is genuinely end-to-end encrypted between the two BaleVPN peers, and in principle it should shield the contents from Bale's forwarding node.

The catch is stated without hedging. There is no certificate authority. Both ends generate self-signed certificates at startup and accept whatever the peer presents. Anyone who can inject themselves into the QUIC handshake path, which includes whoever operates the forwarding server you are routing through, can perform a transparent man-in-the-middle attack by handing each side their own certificate. So the QUIC layer protects against passive eavesdropping by other tenants on the same server, and does not protect against an active adversary at the relay itself.

The conclusion the project draws is that the threat model should be treated as identical to the full VPN case, and that actual confidentiality should come from application-level TLS rather than from the QUIC layer. The practical reading for a user is that choosing SOCKS5 does not move you out of the operator's reach; it only changes which protocol is carrying the bytes.

## The author's own recommendation is a phone number you can throw away

Having established that the call records expose the social graph, the project does something most tools in this space do not: it tells you how to make those records less useful. Register the Bale account used with the tool on a virtual phone number rather than your primary one, so the call metadata cannot be tied back to your real identity.

There is a specific complication, because the account is normally verified by SMS and Iranian SMS gateways often cannot reliably deliver to international numbers. Bale accepts non-Iranian numbers, and for those it delivers the verification code through Telegram instead. The documented order matters. First get a virtual number that can receive SMS, from a paid provider rather than a free throwaway site, since Telegram and Bale block most of the throwaway ones. Then register a Telegram account on that number, because Telegram's own code arrives by SMS and works on real virtual numbers, and set a username so the Bale message can find you. Then register Bale on the same number, which it detects as non-Iranian, and it sends the code as a Telegram message instead of an SMS. Finally enter the code in the app.

Four cautions follow. Telegram is only needed during sign-up, since the app talks to Bale directly afterwards. Keep paying for the number, because losing it means losing the Bale account, and recovery on a number you do not control is described as hard. The account is tied to that number permanently, so pick one you are willing to keep. And the file notes that the same recipe works for signing up for Bale generally, not only for this project. A per-phone-number cost is a real and under-discussed price for this kind of tool.

## The workspace is split by role, and one directory explains the rest

The repository layout is a short list of Rust crates and it reads like a design document. There is a LiveKit tunnel crate, a LiveKit signaling crate, a Bale-specific signaling crate, the VPN crate itself, and a separate Android application crate. Alongside them sit a directory named for reverse engineering, a scripts directory, a docs directory, and an agent instruction file.

The naming tells you what the project actually is. A LiveKit tunnel and LiveKit signaling are off-the-shelf building blocks, since LiveKit is the media stack the call infrastructure is built on. The Bale-specific signaling crate and the reverse-engineering directory are the part that had to be written from observation: Bale's own signalling had to be understood well enough to make its media path carry something other than audio. That is also the honest answer to the question of how stable this can be, because a client of someone else's signalling protocol is tied to whatever that protocol does next.

The Android application is its own crate rather than a wrapper, and the documentation ships in both English and Persian. On the release side the project is on a small version 2 line: 2.1.0 on 2026-05-27, 2.1.1 on 2026-05-29, and 2.1.2 on 2026-06-12, with the last push carrying the same date as the newest tag. That is a project that reached a working state and has not moved since mid-June, which is worth knowing before you plan around it.

## The Makefile does two jobs and explains every flag it passes

The build file is a small, well-commented piece of engineering, and it is where the project's real priorities show. There are two kinds of work: a local build, which is the Rust command line or host binary and the Android APK, the latter of which itself cross-compiles the JNI shim through cargo-ndk; and a sync to a remote machine, which rsyncs the repository to a target you name while excluding the generated artefacts the remote will rebuild for itself.

The rsync invocation is the interesting half, because every flag is justified in a comment rather than left as folklore:

```makefile
RSYNC_FLAGS = -rltzv --delete -e "$(SSH_CMD)" \
    --exclude='.git/' \
    --exclude='target/' \
    --exclude='**/target/' \
    --exclude='node_modules/' \
    --exclude='**/node_modules/' \
    --exclude='bale-vpn-android/**/build/' \
    --exclude='bale-vpn-android/rust/jniLibs/' \
    --exclude='bale-vpn-android/.gradle/' \
    --exclude='bale-vpn-android/.idea/' \
```

Recursive, symlinks preserved, mtimes preserved so that cargo's fingerprinting can skip rebuilds when the source did not actually change, compression in transit, deletion of remote files that no longer exist locally, and one line of output per file because the nicer progress option does not exist in the rsync version macOS ships. The host key policy is trust on first use, which accepts a host it has not seen and rejects a changed key, with a note to drop it if your machines rotate keys often. The SSH key is optional and, when set, restricts the agent to that identity.

One exclusion is the tell. The JNI libraries directory is skipped, which means the cross-compiled native shim is never synced. The APK build is not reproducible from a synced tree, so the remote machine has to run the Android toolchain itself.

## The visible file stops partway through the Persian security section

The documentation is mirrored rather than translated twice, which is the right call for a tool with this audience, and the structure of the page follows the order of a reader's actual decisions: how it works, then what the operator can see, then what to do about the account itself. The English text covers the mechanism, the full privacy analysis including the SOCKS5 caveat, and the account recommendation. After that the Persian mirror begins, and the visible text ends partway through the Persian SOCKS5 paragraph, so anything further in the file is not readable from what is published here.

What that visible portion is heavy on is caveats, and what it is light on is instruction. There is one install path described in a sentence, one mode choice explained in a paragraph, and about four paragraphs on what the messaging operator can observe. That imbalance is the most useful property of the project. A tool that borrows another service's media infrastructure has an unusual amount to disclose, and this one does the disclosing in its own README rather than in a wiki nobody reads.

The smaller signals: one open issue against 401 stars and 85 forks, an MIT licence at the root, an agent instruction file, and a build file that documents its own decisions. Nothing in the visible material claims performance numbers, uptime, or a comparison against other circumvention tools, and the absence is consistent with a project whose selling point is that there is no operator to sell you anything.

## Conclusion

BaleVPN fits a specific and narrow situation: one device has a working connection, another does not, and the two people already trust each other enough to run a relay for each other, because there is no infrastructure to sign up for and no operator between them and the tunnel. It is a poor fit as a privacy tool, and the project says so itself, so anyone reaching for it as anonymity is reading past its own warning. Before you rely on it, check three things yourself: that you understand the relay operator is the messaging service and not you, which means it can see who relays for whom and which hostnames you reach; that anything you send through it is protected by application-level TLS rather than by the tunnel; and that the account you use is one you are willing to lose, since the file is explicit that the account is tied to its phone number and recovery on a number you do not control is hard.

## FAQ

### What is a P2P VPN and how does it work?

In BaleVPN one device runs as the server and provides internet while another runs as the client and consumes it, with no third-party server in between. The link tunnels IP traffic over the voice-call infrastructure of Bale, the Iranian messaging app, so to Bale's own servers the connection looks like a long voice call between two contacts. Both accounts must have each other in their contact lists.

### Is tunnel VPN safe?

The project says to treat it like a corporate VPN whose operator you do not fully trust. The data channel is encrypted with DTLS so traffic is opaque to passive observers and to ISP middleboxes, but Bale's LiveKit server is the forwarding and relay node and has access to the plaintext, so the file calls it fine for IP-level reachability and explicitly not adequate as an anonymity or end-to-end privacy layer.

### What can the Bale messaging service see when I use BaleVPN?

It can see who relays for whom, because every tunnel session is a voice call between two accounts and the call records reveal which account used which relay, when, and for how long. It can see which destinations you connect to, as IP and port plus the hostname in the TLS SNI of any HTTPS request. It can read the contents of traffic that is not itself end-to-end encrypted.

### Does SOCKS5 mode protect my traffic from Bale?

Not against Bale itself. SOCKS5 mode carries traffic inside a QUIC channel that adds TLS 1.3 between the two peers, but there is no certificate authority: both ends generate self-signed certificates at startup and accept whatever the peer presents, so an active party in the handshake path can present its own certificate to each side. The project says to treat the threat model as identical to full VPN mode and rely on application-level TLS.

### Why does the BaleVPN setup ask for a virtual phone number?

So the call metadata cannot be tied back to your real identity, since the project's own privacy note says the call records reveal the social graph. Bale accepts non-Iranian numbers and delivers their verification code through Telegram rather than by SMS, so you register a Telegram account on the virtual number first and then register Bale on that same number. The number must be one you keep paying for, because losing it means losing the account.

## Sources

- [Issues](https://github.com/kookoo1sabzy/BaleVPN/issues)
- [kookoo1sabzy/BaleVPN on GitHub](https://github.com/kookoo1sabzy/BaleVPN)
- [License: MIT](https://github.com/kookoo1sabzy/BaleVPN/blob/main/LICENSE)
- [README](https://github.com/kookoo1sabzy/BaleVPN/blob/main/README.md)
- [Releases](https://github.com/kookoo1sabzy/BaleVPN/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/kookoo1sabzy-balevpn
