MeshAid is not security-audited and is not approved for high-risk deployment. Its useful safety properties are implementation goals backed by local tests, not guarantees.
Do not disclose suspected vulnerabilities in a public issue. Use GitHub's Security > Report a vulnerability form so the maintainer can investigate through a private security advisory. If private reporting is not enabled, open a minimal public issue asking the maintainer to enable it, without including exploit details, keys, identities, or message contents.
Short text communication among nearby Android devices when internet access is unavailable or jammed:
- A Public Lobby for non-sensitive discovery and announcements.
- Encrypted direct messages to a currently reachable mesh peer.
- Small Trusted Circles whose devices are admitted in person by an organizer.
- No central service, account database, contact upload, GPS feature, or Android internet socket permission.
- MeshAid uses its own BLE service/characteristic UUIDs and a separate Wi-Fi Aware service name, so BitChat cannot discover MeshAid as part of its application mesh.
- Public messages carry Ed25519 signatures from process-ephemeral alias keys. The UI always labels those aliases unverified.
- Direct messages travel inside a peer-addressed Noise session and also carry an Ed25519-signed inner envelope bound to the intended 16-hex peer ID. MeshAid waits for the encrypted session and performs bounded forced handshake retries instead of silently dropping the first message. Version 0.4.1 uses a length-safe MeshAid Noise frame because the inherited one-byte TLV could not carry the signed envelope.
- The Direct UI exposes a signed fingerprint and labels it unverified; an alias alone is never presented as proof of identity. A changed signed identity on the same peer ID is blocked for the current process.
- Each Trusted Circle has a random 256-bit group key and circle-specific member signing keys.
- Trusted Circle messages use AES-256-GCM plus an Ed25519 signature; receivers reject non-member signing keys.
- Admission uses a signed offer, signed device request, explicit organizer approval, X25519 key agreement, HKDF-SHA-256, and a device-bound AES-GCM welcome.
- The initial offer QR never contains the group key. Organizer-side offers expire after five minutes and are marked consumed after approval.
- Re-scanning the same invite resumes the same pending cryptographic join identity. The organizer refuses a second approval for an already-admitted signing key and warns when a new identity reuses an existing display name so fingerprints can be compared.
- An organizer can revoke a member. The current MVP increments the circle epoch, creates a new random group key, invalidates pending admissions, and resets the new epoch to the organizer alone; every retained member must be re-invited.
- Version 0.4.2 broadcasts an admin-signed, unencrypted epoch-reset notice containing only the opaque circle ID and new epoch. Old members authenticate it using their saved admin key, delete the obsolete group key/messages/admission state, and retain a minimal “rejoin required” epoch tombstone. Creating a later invite rebroadcasts the current reset for devices that were offline.
- QR admission version 2 binds the offer, request, encrypted welcome, and pending state to a specific circle epoch. A signed newer-epoch invite can replace stale local membership; current/older epochs and a changed organizer key are rejected.
- Circle keys and saved decrypted circle messages are in one AES-GCM authenticated file protected by a non-exportable Android Keystore key. Atomic replacement protects against partial writes.
- Android backup and device-transfer rules exclude all app state. The official activity uses
FLAG_SECURE, disables recent-task screenshots, and opts out of third-party overlays on Android 12+. - Sensitive inherited Noise key-state and plaintext-message logs were removed at source; R8 strips all remaining Android log calls from release artifacts.
- No global message key or release-signing secret is embedded in source or APKs. The protected release job signs already-built artifacts without checking out or executing repository code.
- The official client hides Public Lobby messages older than its current session and Trusted Circle messages older than the local member's admission time.
- BLE/Noise transport keys rotate on each fresh process. Trusted Circle member names are not present in the outer circle-message envelope.
- Incoming envelopes have size and age limits, duplicate suppression, membership checks, and local public-message flood controls. Public posts are limited to 280 Unicode characters, the official client enforces a five-second local send cooldown, and receivers apply per-session-identity arrival/duplicate limits before displaying posts.
- MeshAid owns the active transport delegate. Rejected or undecryptable MeshAid packets do not reach the inherited chat UI's pre-validation haptic/notification path.
- QR verification and welcome decryption run off the main UI thread with a visible processing state. Successful request/welcome scans close the scanner instead of leaving an empty dialog.
- No forward secrecy or post-compromise security for group messages. Version 0.4 uses an epoch group key. A stolen current group key can decrypt retained messages from that epoch.
- Revocation is disruptive in this MVP. It rotates the group key and resets the current circle to the organizer, so all members that remain trusted must complete QR admission again. Revoked devices can still communicate with each other on their abandoned old epoch; the organizer cannot erase keys or messages already stored on their phones.
- Revocation notification is best-effort mesh traffic. An offline old device may temporarily display ghost membership and can exchange old-epoch messages with other unupdated/offline devices until it receives a signed reset or scans a newer signed invite. It cannot decrypt or send into the organizer's new epoch.
- Epoch-reset notices reveal that an opaque circle identifier changed epoch and when the notice was transmitted. They do not name the circle/member or carry a group key, but nearby observers can correlate radio timing and the already-visible outer circle identifier.
- Newcomer history blocking is a client policy, not cryptographic backward secrecy. The official client rejects messages dated before the current session/admission, but a modified client that receives the current epoch key and has retained old ciphertext from that same epoch might decrypt it. Rotate-on-admission or a reviewed group protocol is required for cryptographic history exclusion.
- The organizer is a single admission authority. Losing that device prevents adding members; compromising it allows hostile admissions.
- Public Lobby messages are not confidential. Attackers can create many aliases, spam, observe, copy, delay, selectively relay, or suppress them. Local rate limiting is not Sybil resistance.
- Public flood controls are local usability defenses, not network-wide moderation. Restarting the app creates a fresh public signing identity, and an attacker with multiple devices or modified clients can bypass per-identity limits. Receivers may still expend radio/battery resources on traffic that is later hidden.
- Direct-message confidentiality depends on the inherited Noise implementation, which has not been independently audited for MeshAid. The displayed signed alias key is process-ephemeral and does not prove a real-world identity; users must compare fingerprints in person over an independent channel.
- Direct-message history is session-only in version 0.4.1 and disappears when the app process is restarted. The UI does not yet expose authenticated delivery or read status. The previous send failure was reproduced as the legacy 255-byte TLV rejecting MeshAid's signed envelope and is covered by a length-safe framing regression test, but 0.4.1 still needs a sustained two-phone DM field test.
- MeshAid 0.4.1+ direct messages use a new Noise payload type and require both endpoints to run 0.4.1 or newer.
- MeshAid 0.4.2 and newer use
MESHAIDQR2admission codes. Older QR1 builds cannot participate in the epoch-aware rejoin flow; every device in a tested circle should be upgraded before revocation/re-admission. - MeshAid 0.4's isolated radio namespace remains intentionally incompatible with MeshAid 0.3.0 and older; mixed versions will not find each other.
- Bluetooth presence, traffic timing, packet size, radio identifiers during a running session, and physical proximity remain observable. Encryption does not hide that devices are communicating.
- Store-and-forward delivery is best effort. Android background limits, vendor firmware, interference, jamming, low battery, and sparse device density can delay or prevent messages.
- A compromised or unlocked phone, hostile OS, accessibility service, keyboard, camera, screenshot, notification listener, or physical coercion can expose content.
- Open source means the protocol and implementation can be inspected and modified. Obfuscation is not a security boundary. A rooted or actively hooked device can ask the running app to use its keys or read decrypted process memory even when Android Keystore prevents exporting the wrapping key.
- Anyone can publish a modified fork, but it cannot update an official installation without the official Android signing key. Fresh installers must verify the release checksum, provenance, and published signing-certificate fingerprint to avoid a look-alike APK.
- Private-data wipe deletes app-accessible state and its Keystore key; it is not guaranteed forensic erasure of flash remnants or screenshots.
- A private-data wipe intentionally creates a new cryptographic identity. MeshAid does not use a persistent hardware identifier to track a wiped phone; an organizer must treat it as a new device, compare the displayed fingerprint, and revoke the old identity if appropriate.
- The inherited BLE mesh, packet parser, fragmentation, gossip, and background-service code has not been independently audited. Unused upstream Tor/Nostr/geohash/media code remains in the source tree and debug binary, though it is not exposed and the manifest removes internet, microphone, storage, and Wi-Fi permissions.
- QR proximity authenticates the device shown in person; it does not prove a legal name, organization, or intent. Users must check the displayed person/device themselves.
- The three-display QR admission ceremony is intentional: offer, device-bound signed request, then device-encrypted welcome. Removing the final scan would require a different authenticated return channel or would put circle key material into an earlier transferable code.
- Replace the epoch group key design with a reviewed group protocol providing forward secrecy, post-compromise security, cryptographic history exclusion for new members, and seamless authenticated membership changes (for example, an appropriate MLS implementation).
- Independent cryptographic/protocol, Android, BLE, and privacy-metadata audit.
- Fuzz packet, fragmentation, gossip, public/direct/circle envelopes, encrypted storage, Noise session transitions, and all QR parsers.
- Multi-device adversarial tests for replay, request/welcome copying, Sybil flooding, malicious members, reordering, clock skew, resource exhaustion, jamming, and lost organizer/member devices.
- Delete unreachable upstream network/media/location code and unused dependencies; produce a minimal reviewable module.
- Reproducible release builds, protected signing keys, signed provenance, a documented offline update path, and a monitored vulnerability disclosure address.
- Field drills with the exact phone models, Android versions, battery settings, crowd density, and physical area expected in use.
- Local legal and operational review for the intended deployment region.
The repository maintainer must enable GitHub private vulnerability reporting and monitor security-advisory notifications before announcing a public beta.