Security policy
Model (read this before reporting “messages aren’t encrypted”)
Section titled “Model (read this before reporting “messages aren’t encrypted”)”chIRpChat is public chat infrastructure: message content is plaintext by charter; what the protocol protects is origin authenticity and infrastructure integrity. The full design, including exactly what the 8-byte chat tags do and do not prove, is in docs/IDENTITY.md. Summary of intended guarantees:
- Client↔router traffic is authenticated by per-session MACs (SipHash over a DH-derived key); third parties cannot forge a registered user’s messages without compromising a session or a router.
- Published 64-bit chat-tag keys are a spoofing tripwire, not a signature; forgeries are cryptographically exposed by Ed25519-signed checkpoints within a bounded window (≤ 32 messages / 15 minutes).
- Channel ownership, key rotation, device revocation, and remote admin are full Ed25519 operations.
- Router federation links are mutually authenticated; plaintext on the wire is a feature, integrity is not optional.
Reports that the above fails to hold are security bugs. Reports that the above is the design are answered by the docs.
Out of scope by design: confidentiality of message content, traffic analysis resistance, RF jamming.
Scoped confidentiality exception: admin / oper
Section titled “Scoped confidentiality exception: admin / oper”The plaintext charter covers chat. A narrow, opt-in exception exists for
administrative traffic where an eavesdropper on the LAN (or a compromised
router observing LPP frames) reading an admin rtN set identity.revoke <uid>
or an oper-auth challenge is a real problem that signatures alone do not solve
— signatures prove who sent it, not that only the peer can read it.
The scoped-confidentiality path reuses the already-vendored primitives
(X25519 ECDH + HMAC-SHA256, both in core/) rather than adding a new
cryptographic dependency (AGENTS.md rule 6 keeps the external surface at
RadioLib + orlp/ed25519 on purpose). The key is derived exactly the way the
session MAC key is today (derive_session_key, IDENTITY.md §2), and the
plaintext is sealed with an authenticated-encryption construction over that
key. Two concrete options, both reusing existing primitives:
- HMAC-SHA256 encrypt-then-MAC: a counter-mode keystream from
HMAC-SHA256(key, counter)XORed into the plaintext, with an HMAC-SHA256 tag over (nonce ‖ ciphertext). No new code beyond composing primitives the tree already ships and tests. - Vendor a single-file AEAD (XChaCha20-Poly1305): the conventional choice; follows the orlp/ed25519 single-file-vendoring precedent but is a new dependency that needs explicit operator sign-off (AGENTS.md rule 6).
The framework seam is designed so the primitive is swappable behind one interface; the choice between (1) and (2) is an operator decision recorded in this file. Until that choice is made and a construction lands, admin/oper traffic remains signed-but-plaintext (the current state): authentic and tamper-evident, readable on the wire. Chat traffic is unaffected — the plaintext charter holds for it unconditionally.
This exception is scoped to: oper-auth challenge/response, sensitive
admin set payloads (revocations, key material), and oper↔server control. It
is never applied to channel messages, DMs, presence, or telemetry.
Reporting
Section titled “Reporting”Email clive@ansible.org (maintainer) with subject [chIRpChat SECURITY], or
use GitHub private vulnerability reporting once the repo is public. Include
a reproduction; protocol-level issues ideally come with a failing test
against lrc-core (the in-process network sim in tests/test_node.cpp
makes most attacks expressible in ~30 lines).
- Acknowledgment target: 7 days.
- Fix-or-public-advisory target: 90 days, negotiable for radio-deployed fleets (nodes on hills are slow to reflash; OTA is on the roadmap).
Hardening notes for operators
Section titled “Hardening notes for operators”- Identity seeds live in
--state-dir(lrcd) or NVS (firmware). Protect them like SSH keys;*.lrckeyis gitignored for a reason. admin.quorum=2enables two-operator signing for remote admin.- Routers should pin
operators=keys, not nicks. - TCP peer links accept any peer that completes the RK handshake with a
key in your
peers=roster — keep the roster tight.