Skip to content

Security: xero/covcom

SECURITY.md

COVCOM Security Policy

Table of Contents


Supported Versions

This policy covers COVCOM and its cryptographic dependency leviathan-crypto, both maintained by the same author and released in tandem. Support is rolling, so only the current release is supported. A vulnerability in either project triggers a coordinated release that immediately deprecates the previous version.

Version Status Reason
v3.1.0 ✓ supported Latest version
v3.0.0 ✗ deprecated insufficient rendering sanitization
v1.0.0 ✗ deprecated XChaCha20 seal wasn't key-committing, thus vulnerable to salamander style partitioning-oracle attacks
v0.0.1 ✗ deprecated public beta

Caution

Deprecated versions receive no patches. Upgrade promptly.

Deprecation lands on every channel at once: the outgoing Docker tag is replaced by a tombstone image, and the outgoing covcom and covcom-server npm versions are deprecated in lockstep with the same reason string.

Compiled Binaries

The standalone server and CLI binaries embed the Bun runtime they were compiled with. A Bun security fix that touches the network, TLS, or WebSocket stack does not reach a published binary until the project rebuilds it, so a relevant Bun security release triggers a COVCOM patch release. The rolling policy above covers the rest: only the current release's binaries are supported, and the current release always carries the current runtime. The npm platform packages (@covcom/cli-*, @covcom/server-*) wrap these same binaries and carry the same frozen runtime, so the policy covers them identically.

The other run modes patch on their own channels. Source mode picks up Bun fixes when the host's bun updates; the Docker image picks them up on each image rebuild.


Reporting a Vulnerability

Important

Please do not open a public issue for security vulnerabilities.

Private Advisory (preferred)

Use GitHub's private vulnerability reporting form: https://github.com/xero/covcom/security/advisories/new

This opens a private channel between you and me, and you will receive a response promptly. If the vulnerability is confirmed, we will collaborate to fully understand the issue, including a review of proposed fixes, so you can track and validate firsthand. Before any public advisory is published, we will agree on a coordinated disclosure timeline. After disclosure, you are encouraged to publish your own write-up, blog post, or research notes, for full hacker scene credit.

Direct Contact

If you prefer to contact me directly:

  • Email: x﹫xero.style · PGP: 0xAC1D0000
  • Matrix: x0﹫rx.haunted.computer

Note

Encrypted communication is welcome and preferred for sensitive reports.

Scope

In scope:

  • Vulnerabilities in COVCOM's web client, CLI, or server
  • Vulnerabilities in the COVCOM wire protocol or session handshake
  • Cryptographic weaknesses in the ratchet implementation or key derivation
  • Vulnerabilities in leviathan-crypto primitives or the WASM layer
  • Protocol design flaws (an unsound design itself counts)
  • Dependency vulnerabilities that affect COVCOM's security properties
  • Invite format weaknesses (enumeration, forgery, replay)

Out of scope:

  • Bugs in leviathan-crypto unrelated to COVCOM's use of it. Please report those in the leviathan-crypto repository
  • The non-goals listed in the threat model: endpoint security, traffic analysis, server availability attacks, multi-session correlation
  • Attacks requiring physical access to a participant's device
  • Social engineering attacks against participants
  • APT-level nation-state adversaries with quantum computing capability today (ML-KEM-768 addresses future quantum, not present-day state actors with unlimited classical resources)
  • Spam or denial-of-service against publicly hosted instances

Cryptographic Foundations

All cryptographic operations in COVCOM are provided by leviathan-crypto, a zero-dependency TypeScript/WASM library by the same author. There are no third-party cryptographic dependencies.

The active primitive set:

Primitive Purpose
XChaCha20-Poly1305 Message and file encryption
ML-KEM-768 (FIPS 203) Post-quantum key encapsulation
HKDF-SHA-256 Key derivation throughout
Seal+MlKemSuite Chain seed distribution
Ed25519PreHashSuite Identity-claim and per-message signing
BLAKE3 Identity-log chain hash and fingerprint derivation
SHA-256 Merkle Per-sender transcript log

The protocol implements the Sparse Post-Quantum Ratchet from the Signal Double Ratchet spec (§5, Revision 4) with a Sender Keys group messaging model.

Tip

The cryptography reference documents how each primitive is constructed and composed. The protocol specification covers the wire format, session handshake, and ratchet flow.


Threat Model

The protocol provides

Message confidentiality. Passive and active network adversaries learn nothing from the wire.

Forward secrecy. Past messages stay unrecoverable from current state.

Post-compromise security. State heals at every KEM ratchet boundary.

Harvest-now-decrypt-later resistance. ML-KEM-768 guards against future quantum decryption.

Enumeration resistance. A 2^128 room secret space defeats guessing.

Session anonymity. No persistent identity keys are visible to the server.

Per-message provenance. Every broadcast carries a detached Ed25519 signature, verified before AEAD, over the signed bytes counter || epoch || sender || ts || ciphertext.

Split-view detection. Each peer's identity claims form a BLAKE3-chained log, surfaced as an 8-colour fingerprint for out-of-band comparison.

Untrusted-content rendering. Peer-controlled display text (usernames, message bodies, filenames) never becomes markup in the web client or terminal escapes in the CLI. This defeats XSS, terminal escape injection, and bidi or homoglyph display-name spoofing.

Validated client configuration. The CLI parses its config file defensively. Theme colors must match a closed set of forms (ansi16 0-15, 256 0-255, or #rrggbb hex), so a config value can never reach the terminal as an arbitrary escape sequence through the color path. An invalid value falls back to its slot default instead of emitting a broken escape, and a config file that fails to parse falls back to defaults rather than being silently discarded. The ignored settings are named in a modal on launch, so the problem is visible instead of manifesting as garbled output.

Clean teardown. Session keys live only in memory and are wiped on every exit path (Ctrl+C, /exit, SIGTERM, and fatal errors), not just a graceful disconnect. The CLI also restores the terminal on the way out, leaving no chat transcript on screen or in scrollback.

The protocol does not protect against

Endpoint compromise. Malware or physical device access defeats any transport security.

Traffic analysis. Timing, message volume, and session duration stay observable.

Membership lies. A malicious server can misreport who is in a room.

Cryptographic deniability. Signatures bind authorship, so messages are not deniable.

Multi-session correlation. Out-of-band means can still link separate sessions.

Note

See the full Dolev-Yao style adversary analysis in THREAT-MODEL.md.


Deployment Hardening

The protocol's guarantees are cryptographic and hold against the network. The Docker image adds a hardened transport and delivery layer on top, so a default deployment does not weaken them.

Automatic TLS. Caddy terminates TLS and provisions a certificate over ACME for $DOMAIN on first start. Plain HTTP on port 80 redirects to HTTPS. The certificate and ACME account live on the covcom_caddy_data volume, so a restart reuses them instead of re-provisioning and tripping Let's Encrypt rate limits.

Single-origin relay. The container serves the web client and proxies the WebSocket relay on one origin. The client derives the socket scheme from the page it loaded, so an HTTPS page always connects over wss:// and never falls back to plaintext ws://.

Strict Content Security Policy. The built client ships default-src 'none' with no worker-src, a hashed inline script instead of 'unsafe-inline', and a connect-src confined to the same origin, wss:, and loopback ws://. All cryptography runs as main-thread WASM under wasm-unsafe-eval; no worker is spawned. COVCOM is the single-file SPA worked example in leviathan-crypto's CSP reference, which covers the full policy and its rationale.

Clickjacking protection. Caddy sends X-Frame-Options: DENY. The equivalent frame-ancestors directive is silently ignored when delivered in a <meta> CSP, so the protection is enforced as a real response header.

Runtime-only configuration. The image takes no build arguments. Secrets such as ADMIN_TOKEN are passed as runtime environment variables and are never baked into an image layer. The runtime image carries no build or development tooling.

Warning

The TLS termination and the X-Frame-Options header come from the bundled Caddy, not the Bun server. If you run the server directly behind your own reverse proxy (the no-docker path), you must terminate TLS and set the equivalent security headers yourself.

There aren't any published security advisories