bitchat is a messaging app that keeps working when the internet does not. Phones running it find each other over Bluetooth Low Energy and pass messages along, up to seven hops, so a message can reach someone out of direct range through the phones in between. The README names protests, disasters and remote areas as uses, and it suits any crowded place where the network gives up. There are no accounts, no phone numbers and no central servers.
When you are online it can also use Nostr, an open network of public relays, for location-based channels at block, neighbourhood, city or country level, and for private messages when Bluetooth is out of reach. Private messages are end-to-end encrypted, with the Noise Protocol on the mesh. It has IRC-style commands such as /msg, /who and /slap, and a triple-tap wipes all data instantly.
bitchat is released into the public domain under the Unlicense. This repository holds the iPhone and Mac app and has about 37,000 stars and 59 contributors since July 2025; version 1.8.0 came out on 23 October 2026. An Android version is on the Play Store.
- Repository: github.com/permissionlesstech/bitchat
- Licence: Unlicense (The Unlicense)
- Language: Swift. Stars: 37.1K. Forks: 5,889. Last push: Nov 8, 2026.
- Scan: safe, Nov 10, 2026, commit 04995f6
Who it is for
Groups at events, protests, campsites or anywhere the network is overloaded, people preparing for outages and emergencies, and anyone curious about chatting without an account or a company in the middle.
Getting started
1. Get it on iPhone, iPad or Mac from the App Store
https://apps.apple.com/us/app/bitchat-mesh/id67482196222. Or on Android from the Play Store
https://play.google.com/store/apps/details?id=com.bitchat.droid3. Optional: check a build against the source yourself
https://github.com/permissionlesstech/bitchat/blob/main/docs/VERIFYING-A-BUILD.mdThe README asks you to install only from the App Store or a build you verified, because the repository has faced takedown demands and unofficial mirrors cannot be checked. Our scan covers this repository's source, not the store apps.
Safety scan
We cloned permissionlesstech/bitchat at commit 04995f6 on Nov 10, 2026 and ran the checks described on the GitHub Tools page: credential patterns, decode-and-execute code, install-time scripts, committed binaries, risky CI workflows, every host the code talks to, known vulnerabilities in pinned dependencies, and project hygiene. A person read every hit. This is what we found.
- No secret hits and no pattern hits across 670 files and about 171,000 lines, mostly Swift. No install hooks.
- The 3 committed binaries are prebuilt copies of one static library, libarti_bitchat.a, for macOS, iOS and the iOS simulator, about 7 to 15 MB each. It is Arti, the Tor project's Rust implementation, which bitchat uses to send Nostr traffic over Tor where enabled. The build script, localPackages/Arti/build-ios.sh, is in the repo, so you can rebuild it instead of trusting the copies.
- 26 advisories, all in that Arti library's Cargo.lock: 1 high (a crash on a malformed certificate revocation list in rustls-webpki), 7 moderate, 7 low and 11 unrated, mostly unmaintained crates and TLS library issues.
- Read the privacy limits. The whitepaper is unusually frank: the sender ID in every packet comes from a key that never changes, announcements carry nicknames and keys in clear text, so a passive listener nearby can list participants and follow a device from place to place. Messages are encrypted; who is around is not hidden. Location channels share an approximate area through public Nostr relays.
- There is a /pay command for sending a Cashu ecash token you already hold, and pasted Lightning or Cashu payment links show as tappable chips. bitchat has no coin, wallet or token of its own, and its code comments warn against posting ecash in public channels.
- 6 workflows. The scanner flagged one for pull_request_target, but the file only mentions it in a comment saying the job deliberately does not use it; it runs on pull_request with read-only permissions. No third-party actions. A security policy and licence are present.
What the scanner counted
| Check | Result |
|---|---|
| Secrets | None found. |
| Suspicious code | None found. |
| Install-time code | None: nothing runs at install beyond the package manager itself. |
| Committed binaries | 3 executable or compiled objects committed; listed under the raw findings. |
| CI workflows | 6 workflows. 1 uses pull_request_target, none check out the pull request head. No third-party actions. |
| Network hosts | 15 distinct hosts referenced from source; most often unlicense.org, mint.example.com, raw.githubusercontent.com, www.noiseprotocol.org. No URLs to bare IP addresses. |
| Known vulnerabilities | 26 advisories across 465 pinned packages: 0 critical, 1 high, 7 moderate, 7 low, 11 unrated. localPackages/Arti/Cargo.lock: 465 packages, 26 advisories. |
| Project hygiene | Has security policy, licence file. Missing automated dependency updates, CodeQL, contributing guide. |
| OpenSSF Scorecard | Not scored: the project is not in Scorecard's weekly index. |
The raw findings
Every hit the scanner wrote out, with a link to the exact line at the scanned commit. Secrets candidates are redacted.
Committed binaries (3)
localPackages/Arti/Frameworks/arti.xcframework/macos-arm64_x86_64/libarti_bitchat.a: Mach-O, 15 MBlocalPackages/Arti/Frameworks/arti.xcframework/ios-arm64_x86_64-simulator/libarti_bitchat.a: Mach-O, 14 MBlocalPackages/Arti/Frameworks/arti.xcframework/ios-arm64/libarti_bitchat.a: .a, 7 MB
Worst known vulnerabilities (24 of 26)
| Advisory | Severity | Package | Summary |
|---|---|---|---|
| GHSA-82j2-j2ch-gfr8 | high | rustls-webpki@0.103.8 | rustls-webpki: Denial of service via panic on malformed CRL BIT STRING |
| GHSA-434x-w66g-qw3r | moderate | bytes@1.11.0 | bytes has integer overflow in BytesMut::reserve |
| GHSA-4grx-2x9w-596c | moderate | rsa@0.9.10 | Marvin Attack: potential key recovery through timing sidechannels |
| GHSA-2mjx-qc3c-rqvc | moderate | rustls@0.23.36 | Rustls: TLS 1.3 handshake messages incorrectly accepted across encryption level boundaries |
| GHSA-c8m5-c952-6cm4 | moderate | rustls@0.23.36 | Rustls: Session Debug formatting exposes TLS master secrets and resumption PSKs |
| GHSA-pwjx-qhcg-rvj4 | moderate | rustls-webpki@0.103.8 | webpki: CRLs not considered authoritative by Distribution Point due to faulty matching logic |
| GHSA-7gcf-g7xr-8hxj | moderate | serde_with@3.16.1 | serde_with: KeyValueMap serialization panics on empty sequence or map entries |
| GHSA-r6v5-fh4h-64xc | moderate | time@0.3.45 | time vulnerable to stack exhaustion Denial of Service attack |
| GHSA-3288-p39f-rqpv | low | keccak@0.1.5 | Unsoundness in opt-in ARMv8 assembly backend for `keccak` |
| GHSA-cq8v-f236-94qc | low | rand@0.8.5 | Rand is unsound with a custom logger using rand::rng() |
| GHSA-cq8v-f236-94qc | low | rand@0.9.2 | Rand is unsound with a custom logger using rand::rng() |
| GHSA-h2v8-394m-p7vv | low | rustls@0.23.36 | Rustls: Brotli certificate decompression can allocate an attacker-controlled amount of memory up to 1 GiB before authent… |
| GHSA-w44r-93j7-qv28 | low | rustls@0.23.36 | rustls: An unauthenticated ServerHello poisons the per-name key-exchange record, so later ClientHellos carry only a clas… |
| GHSA-965h-392x-2mh5 | low | rustls-webpki@0.103.8 | webpki: Name constraints for URI names were incorrectly accepted |
| GHSA-xgp8-3hg3-c2mh | low | rustls-webpki@0.103.8 | webpki: Name constraints were accepted for certificates asserting a wildcard name |
| RUSTSEC-2025-0141 | unknown | bincode@2.0.1 | Bincode is unmaintained |
| RUSTSEC-2026-0204 | unknown | crossbeam-epoch@0.9.18 | Invalid pointer dereference in `fmt::Pointer` impl for `Atomic` and `Shared` when the underlying pointer is invalid |
| RUSTSEC-2026-0387 | unknown | crypto-bigint@0.5.5 | Multiple timing variability issues in operations intended to be constant-time |
| RUSTSEC-2026-0221 | unknown | event-listener@5.4.1 | `event-listener` allows `!Send` tags to cross thread boundaries via `StackSlot` |
| GHSA-72w2-rjgg-q729 | unknown | libsqlite3-sys@0.35.0 | `libsqlite3-sys` via C SQLite CVE-2026-119375 |
| RUSTSEC-2026-0186 | unknown | memmap2@0.9.9 | Unchecked pointer offset in crate `memmap2` |
| RUSTSEC-2024-0436 | unknown | paste@1.0.15 | paste - no longer maintained |
| RUSTSEC-2026-0441 | unknown | pin-utils@0.1.0 | `pin-utils` is unmaintained |
| RUSTSEC-2026-0173 | unknown | proc-macro-error2@2.0.1 | proc-macro-error2 is unmaintained |
Workflows worth a look
- .github/workflows/validate_georelays.yml: pull_request_target
By the numbers
| Stars | 37.1K |
|---|---|
| Forks | 5,889 |
| Contributors | 59 |
| Commits | 1,088 |
| Open issues | 48 |
| Open pull requests | 127 |
| Releases | 21 |
| Latest release | v1.8.0 |
| Licence | Unlicense |
| Main language | Swift |
| Project age | 1 year |
| Last push | Nov 8, 2026 |
| Tracked files | 670 |
| Lines of code | 170.8K |
| Checkout size | 47 MB |
Lines by language: Swift 163.9K, Markdown 2,742, JSON 991, YAML 926, Shell 682, Python 611.
Questions
Is bitchat free?
Yes. The app is free on the App Store and Play Store, there is no account, and the code is in the public domain under the Unlicense.
How far can a bitchat message travel without internet?
Bluetooth reaches a short distance on its own, but each phone running bitchat relays messages, up to seven hops. In a crowd, a message can travel well beyond your own phone's range. With no other phones nearby, it only reaches people in direct range.
Is bitchat anonymous?
Not fully, and the project says so. Message contents are encrypted, but a nearby device can see who is broadcasting and track a phone between places because its ID does not rotate. Do not rely on it to hide that you are there.
Does bitchat need internet at all?
No for the Bluetooth mesh, which works fully offline with nearby phones. Location channels and private messages to people out of Bluetooth range use the internet through Nostr relays.
This post is part of GitHub Tools, where every repository is cloned and scanned before it is written up. The scan is a snapshot of one commit on one day; the repository has moved on since, so check it before you install.
