# BitChat Security Architecture: Threat Model, Key Risks, and Code-Level Mitigations

> Explore BitChat's security architecture. Understand threat models, key risks like identity linkability and metadata exposure, and code-level mitigations for this innovative messaging system.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: architecture
- Published: 2026-08-01

---

**BitChat's dual-layer BLE mesh and Nostr protocol design creates persistent identity linkability risks, lacks forward secrecy in offline message sealing, and exposes metadata at the radio and relay levels despite strong transport encryption.**

BitChat, developed by permissionlesstech, implements a decentralized messaging system that routes messages through Bluetooth Low Energy (BLE) mesh networks and the Nostr protocol. Understanding the security implications of BitChat's architecture requires examining how its **identity management**, **transport layers**, and **key storage** interact to create both defensive strengths and attack surfaces.

---

## Identity and Key Management Risks

BitChat's identity system creates long-term traceability vulnerabilities that persist across sessions and locations.

### Static Peer IDs Enable Long-Term Correlation

Each device generates a long-term **Curve25519 static key** for Noise key agreement and an **Ed25519 signing key**, both stored in the device Keychain. The 8-byte peer ID derives directly from the first 8 bytes of the SHA-256 fingerprint of this static key.

According to [[`WHITEPAPER.md`](https://github.com/permissionlesstech/bitchat/blob/main/WHITEPAPER.md) §3](https://github.com/permissionlesstech/bitchat/blob/main/WHITEPAPER.md#33-identity), this peer ID **never rotates** while the key persists. This design choice enables passive observers to **link a device across time and locations**—a fundamental privacy limitation in the current architecture.

### Absence of Forward Secrecy in Courier Messages

When messages cannot be delivered directly, BitChat seals them using **Noise X** to the recipient's static key and stores them with intermediate "courier" peers. As documented in [[`WHITEPAPER.md`](https://github.com/permissionlesstech/bitchat/blob/main/WHITEPAPER.md) §5.2](https://github.com/permissionlesstech/bitchat/blob/main/WHITEPAPER.md#52-offline-seals-noise-x), these **sealed courier envelopes lack forward secrecy**:

- If the static key is compromised (including via a failed panic wipe), **all past undelivered traffic** becomes decryptable
- The damage is not limited to future communications, but extends retroactively to any sealed messages still in the delivery chain

---

## BLE Mesh Broadcast Vulnerabilities

The proximity-based transport layer leaks substantial metadata despite packet-level authentication.

### Cleartext Announcements Expose Device Presence

BLE mesh packets are signed and carry the 8-byte sender ID, flooded with TTL clamped to 5 in dense networks. However, [[`WHITEPAPER.md`](https://github.com/permissionlesstech/bitchat/blob/main/WHITEPAPER.md) §4.1-4.5](https://github.com/permissionlesstech/bitchat/blob/main/WHITEPAPER.md#41-45-presence) documents that **announcements broadcast static keys and nicknames in cleartext**:

- Anyone within radio range can **enumerate participants** without joining the network
- Repeated observation of sender IDs enables **movement tracking** across multiple encounter locations
- Announced neighbor lists reveal topological relationships between devices

### Flood Control Does Not Hide Metadata

BitChat implements TTL clamping, jitter, deduplication, and fan-out subsetting to prevent denial-of-service. These mechanisms protect availability but **do not provide metadata protection**: packet length, timing, and sender-recipient pairs remain observable to radio-level adversaries.

---

## Nostr and Tor Transport Considerations

The internet-facing path introduces traffic analysis risks even when encryption is properly implemented.

### Relay-Level Metadata Exposure

Private messages use a proprietary "private-envelope" format (Nostr kinds 13/14/1059) with **XChaCha20-Poly1305 encryption** routed over public Nostr relays. Per [[`WHITEPAPER.md`](https://github.com/permissionlesstech/bitchat/blob/main/WHITEPAPER.md) §5.3](https://github.com/permissionlesstech/bitchat/blob/main/WHITEPAPER.md#53-nostr-path):

- Relays see only opaque ciphertext
- However, the **outer envelope exposes the recipient's Nostr public key**, enabling traffic analysis and delivery-pattern inference

### Tor Integration Is Conditional

When enabled, Tor wraps HTTP traffic to relays in anonymizing circuits. Critical caveat: **if Tor is disabled or circuits fail, traffic bypasses anonymity entirely**, exposing source IP addresses to relays. The [[`AppRuntime.swift`](https://github.com/permissionlesstech/bitchat/blob/main/AppRuntime.swift)](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/App/AppRuntime.swift) start-up logic attempts to coordinate this, as shown below.

---

## Code-Level Security Mechanisms

BitChat implements several runtime protections to mitigate architectural risks. These mechanisms appear in [[`AppRuntime.swift`](https://github.com/permissionlesstech/bitchat/blob/main/AppRuntime.swift)](https://github.compermissionlesstech/bitchat/blob/main/bitchat/App/AppRuntime.swift), which serves as the central composition root for transport coordination.

### Conditional Tor Activation

Tor start-up is gated on user preference and foreground state to prevent accidental clearnet leakage:

```swift
if TorManager.shared.isAutoStartAllowed() && !TorManager.shared.isReady {
    TorManager.shared.ensureRunningOnForeground()
}

```

*Source: [[`AppRuntime.swift`](https://github.com/permissionlesstech/bitchat/blob/main/AppRuntime.swift#L14-L18)](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/App/AppRuntime.swift#L14-L18)*

This pattern ensures that automatic Tor protection does not activate unexpectedly when the user expects anonymity, but it also means **user error or misconfiguration directly impacts security**.

### Screenshot Privacy Protection

The runtime intercepts screenshot events to prevent accidental UI leakage:

```swift
func handleScreenshotCaptured() {
    if appChromeModel.isLocationChannelsSheetPresented {
        appChromeModel.triggerScreenshotPrivacyWarning()
        return
    }
    if appChromeModel.isAppInfoPresented { return }
    chatViewModel.handleScreenshotCaptured()
}

```

*Source: [[`AppRuntime.swift`](https://github.com/permissionlesstech/bitchat/blob/main/AppRuntime.swift#L26-L36)](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/App/AppRuntime.swift#L26-L36)*

This defends against **shoulder-surfing and accidental disclosure** of location-sensitive channel information.

### Secure Logging Infrastructure

The [`BitLogger`](https://github.com/permissionlesstech/bitchat/tree/main/localPackages/BitLogger) package provides mandatory log sanitization through [`String+Sanitization.swift`](https://github.com/permissionlesstech/bitchat/blob/main/localPackages/BitLogger/Sources/String%2BSanitization.swift):

```swift
SecureLogger.log("Attempting connection to peer \(peerID)", category: .network)

```

*Source: [`BitLogger/Sources/SecureLogger.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BitLogger/Sources/SecureLogger.swift)*

This prevents **secret leakage through diagnostic logs**, a common implementation vulnerability in cryptographic applications. However, developers must ensure all logging calls route through this interface—direct `print()` or `OSLog` calls would bypass protection.

---

## Panic Wipe and Deniability

BitChat provides a **panic wipe** mechanism triggered by the user to destroy sensitive state. Per [[`WHITEPAPER.md`](https://github.com/permissionlesstech/bitchat/blob/main/WHITEPAPER.md) §7-8](https://github.com/permissionlesstech/bitchat/blob/main/WHITEPAPER.md#71-78), this deletes:

- Keychain keys (Curve25519 and Ed25519 material)
- Sealed outbox contents
- Public history cache
- Courier mail
- Metrics data

This provides **strong deniability** for device loss or compromise scenarios. However, the security guarantee depends entirely on:

- Correct iOS Keychain deletion behavior
- Complete wiping of the sealed outbox without implementation bugs

Any failure to clear sealed courier envelopes would retain ciphertext decryptable by a recovered static key.

---

## Transport Layer Isolation Architecture

The `AppRuntime` class orchestrates BLE, Nostr, and Tor services to prevent **inconsistent state** that could leak traffic:

- Only one transport is active at a time
- Reconnections are coordinated across the stack
- Start-up and shutdown sequences are centralized

This design reduces the risk of **transport confusion attacks** where a message intended for one path leaks through another. However, any bug in this coordination code—particularly in [[`AppRuntime.swift`](https://github.com/permissionlesstech/bitchat/blob/main/AppRuntime.swift#L13-L31)](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/App/AppRuntime.swift#L13-L31)—could **expose private keys to the wrong transport**, such as sending a Noise-encrypted packet over a public Nostr relay.

---

## Complete Threat Model

| Threat Category | BitChat Exposure | Mitigation Status |
|-----------------|------------------|-------------------|
| **Passive radio eavesdropping** | High—static IDs enable device mapping and social graph inference | Partial—no link-layer anonymity implemented |
| **Key compromise** | Severe—static keys grant access to all past courier-encrypted messages | No forward secrecy planned per whitepaper |
| **Relay traffic analysis** | Medium—recipient key visible, timing patterns analyzable | Tor optional but not mandatory |
| **Flooding denial-of-service** | Low—TTL clamping, jitter, deduplication active | Implemented in BLE mesh layer |
| **Implementation bugs** | Variable—centralized `AppRuntime` reduces error surface | Depends on code review coverage |

---

## Summary

- **BitChat's security implications center on its static identity model**: the SHA-256-derived peer ID enables long-term correlation, and Noise X seals lack forward secrecy, exposing all past courier messages to key compromise.

- **Metadata is the weakest link in the architecture**: BLE broadcasts expose participants and relationships in cleartext, while Nostr relays see recipient public keys even when payload ciphertext is secure.

- **Code-level mitigations depend on correct runtime behavior**: [`AppRuntime.swift`](https://github.com/permissionlesstech/bitchat/blob/main/AppRuntime.swift) coordinates transport isolation, `BitLogger` sanitizes secrets from logs, and conditional Tor activation prevents accidental clearnet exposure—but user configuration errors or implementation bugs in these paths create direct vulnerabilities.

- **Panic wipe provides deniability but not recovery**: device compromise before wipe completion, or incomplete outbox deletion, leaves decryptable material behind.

---

## Frequently Asked Questions

### Does BitChat provide forward secrecy?

No. According to the BitChat whitepaper, offline courier messages use Noise X sealed to the recipient's static Curve25519 key. There is no ephemeral key exchange for these messages, meaning a compromised static key can decrypt any undelivered envelope. The whitepaper §9 identifies rotating on-air identities as future work, but this is not currently implemented.

### Can someone track my location through BitChat?

Yes, under specific conditions. Passive observers within BLE radio range can record your 8-byte peer ID from broadcast announcements. Because this ID is stable and derived from your static key, repeated observations at different times and locations enable movement tracking. The current architecture does not implement MAC address randomization or identity rotation to prevent this.

### What happens if I don't enable Tor?

Without Tor, your Nostr relay traffic—including your source IP address—is exposed directly to whichever relays you use. The private message envelope encryption protects message content, but relays can correlate your IP with your Nostr public key and observe your communication patterns with specific recipients.

### How reliable is the panic wipe feature?

Panic wipe provides strong deniability when executed correctly before device compromise. It depends on iOS correctly deleting Keychain-protected keys and the application completely clearing the sealed outbox. The whitepaper does not specify verification mechanisms to confirm complete deletion, and any implementation bug that skips the outbox wipe would leave decryptable ciphertext behind.