Files
flamenet-messenger-android/SECURITY.md
T
Paul HittandClaude Opus 4.8 251a9f9c4a Multi-device fan-out: merge the directory with fetched bundles, never choose
listDevices returns identity-only stubs — enough for a device we already
have a session with, useless for one we do not, because initiate()
verifies the signed prekey's signature and a stub carries empty bytes.
Choosing between the two lists meant that whenever ANY device already had
a session, every device got a stub, so a device still needing one could
drop out of the fan-out with no partial-delivery warning (the other
device succeeded, so  was non-empty).

The rule is union: full bundle where the key route returned one, stub
otherwise. Found while verifying a two-device pair by hand; the live
suite's 'a message reaches every device a person has' passes either way,
which is why it needed the hand test to surface.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-29 09:29:55 -04:00

46 lines
2.1 KiB
Markdown

# Security
## Reporting a vulnerability
Email **security@flamenetmessenger.com**. Please do not open a public issue for
anything affecting confidentiality or authentication. We acknowledge within 72
hours.
## Status
**Not independently audited.** This Android app has been reviewed in-house and
is covered by the JVM unit suites plus on-device instrumentation, alongside the shared 253-check relay conformance suite and
cross-platform interop tests that run the real engine on both sides.
An internal adversarial audit on 2026-08-29 found and fixed a family of
sender-attribution flaws: the ratchet authenticates a *device*, and the user id
inside a sealed envelope is a claim its author chooses — the two were not bound.
Devices now bind to their user on first proven use, control traffic (delivery
keys, avatars) is refused from an unproven sender, and the key-transparency log
head is verified against a pinned issuer key. Finding that class of bug in-house
is a reason to expect more from outside review, not fewer.
## What the app protects, and what it cannot
Private keys are generated on the device and live in the Android Keystore, which never hands out key material. Message history is
sealed at rest. The app defends against a **malicious or compromised relay**
reading messages, and against a passive adversary recording traffic to decrypt
after a quantum computer exists (when both ends publish a post-quantum
identity — the safety number says which guarantee it covers).
It does **not** defend against:
- **A compromised device.** Malware with your unlock reads plaintext. The app
lock is a speed bump against someone holding your unlocked phone, not
encryption.
- **Metadata.** The relay sees who is addressed and when. Sealed sender removes
the sender from the stored row, not from the network connection.
- **Your correspondent.** Anything you send can be screenshotted, kept, or
repeated by the person you sent it to.
## Verifying what you run
Every byte of the shipped APK's contents reproduces from this source; only the
randomized signing block differs. See `docs/REPRODUCIBLE.md` in the relay repo
and `scripts/verify-build.py` in the Android repo.