Open Free and open source, read the code Get it Donate App help Contact
Messenger
The app
Developers
Project
Legal

A flamenet.io account is not a Flamenet Messenger account. The two sign-ins are separate.

Security

Status

Not independently audited. This engine was written and reviewed in-house. It has a conformance suite (test/conformance.mjs) covering the constructions in docs/SPEC.md, including cross-backend agreement, tamper rejection and downgrade refusal. A passing test suite demonstrates the code does what the spec says; it does not demonstrate the spec is right, and it is not a substitute for review by people who break protocols for a living.

The vendored ML-KEM-768 fallback (vendor/mlkem768-noble.js, from @noble/post-quantum) carries the same caveat, upstream describes it as self-audited, not independently audited. See vendor/PROVENANCE.md.

Reporting a vulnerability

Email security@flamenetmessenger.com. Please do not open a public issue for anything that affects confidentiality or authentication. We will acknowledge within 72 hours.

Threat model

The full model is docs/SPEC.md §11 and §12.1. In brief, this engine defends against a malicious or compromised relay reading message contents, and (in v2) against a passive adversary recording traffic today to decrypt after a quantum computer exists.

It does not defend against:

  • A compromised endpoint. Device keys live on the device. Malware on it reads plaintext.
  • Metadata collection. The relay sees who messages whom, when, and roughly how much. Sealed sender hides the sender from the stored row (§14), but not from the connection that delivered it, and the first message to a new contact is necessarily unsealed.
  • A quantum adversary present during the exchange, where either end is still on the old key alone. Post-quantum authentication (ML-DSA-65, spec §20) is implemented on the web engine, on iOS and on Android as of 0.29: each publishes a post-quantum identity, verifies a peer's, and refuses a downgrade or a substitution. A device that publishes none is treated as classical rather than refused, because refusing them would cut off everyone who has not updated. Two cases therefore stay on Ed25519 alone, where an adversary who can forge signatures in real time can mount an active MITM: a phone that has not taken the update, and a phone restored from a backup made before that release, which keeps the identity it was restored with rather than being given a new one. No client tells you which of the two a conversation is using.
  • A hostile server operator, when the client is a web page served by that operator. This is structural, not a bug: the relay ships the JavaScript that holds the keys, so it can ship different JavaScript to one user. Native clients do not have this property. Any deployment making confidentiality claims to users must be explicit about which client those claims apply to.

File labels: the half of the lattice that is not enforced

The Files screen carries classification labels, and a label set is a claim about which rules hold. Only one of the two holds, so the other is named here instead of implied away. See flamenet-messenger ios#65 and android#15.

No read up is enforced. An object your session label does not dominate is not visible, and by default writes happen at exactly the session label.

The ★-property, no write down, is not enforced. A principal cleared to a high label may open a session at a lower one and write there, carrying down what they read above it. No client stops this, because a session label inside a principal's clearance range is a legitimate session.

This is the half the model exists for. No-read-up stops somebody reaching material above them, which most systems get right. No-write-down stops the material leaking downward through a person who is allowed to see it, which is the threat a lattice is built to contain.

The gap is a decision, not an oversight: a rule enforced on one client and not the other is worse than the gap, and strict enforcement with no downgrade path produces a workaround culture. Doing it properly means an explicit downgrade action with an audit trail. Until that exists, this is written down.

So "implements Bell-LaPadula" would be too round a word. What exists is the simple security property, not the ★-property.

Deployment notes

  • Persist state encrypted. DeviceIdentity.archive() and E2ESession.archive() both contain private key material. localStorage is not an acceptable store.
  • Keep the two prekey pools the same size. A PQ pool smaller than the classical pool drains first and silently downgrades new sessions to the last-resort key. §12.3.
  • Pin minProto per device. Without it, a relay can strip the v2 fields from a bundle and both honest parties will negotiate v1. Pinning is what makes downgrade detectable; first contact remains vulnerable until pqMode is required. §12.7.
  • Rate-limit prekey fetches. GET /e2e/keys consumes a one-time prekey per device per call, so an attacker can drain both pools cheaply. This is unfixed at the protocol layer.
  • Do not claim more than you can show. The spec's §12.10 lists what must actually be run before the corresponding claims are made. An earlier version of this project asserted cross-platform interop in its spec that had never been performed and was, at the time, impossible. Write claims after the runs, not before.
Free and open source · No ads · No phone number · Your own server if you want one