Open Free and open source — read the code

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. v2 makes key agreement hybrid, but identity keys are still Ed25519, so an adversary who can forge signatures in real time can still mount an active MITM. Post-quantum authentication is unimplemented.
  • 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.

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.