Changelog¶
Each release of WaWarden and what it introduced. The format follows
Keep a Changelog, and versions follow
the versioning rules in RELEASING.md.
v0.1.0 to v0.3.0 were development releases: each replaced the one before
it and promised no compatibility. The compatibility promise starts at
v1.0.0. Only the latest minor release line is supported (see
SECURITY.md).
Every release's notes on the
Releases page give its commit,
its image digest and the commands to verify and reproduce it.
wawarden version prints a binary's version.
Contents¶
1.0.0 - 2026-10-12¶
Built from commit 5021d13 with go1.27.2.
Added¶
- Sending text over REST (
POST /v1/chats/{ref}/messages) and the MCP toolsend_message, optionally as a reply in the same chat. Only a client with write chats seessend_message. - Idempotency keys for sends, kept for 24 hours per client.
- The pacer, per-client and global send limits, and the first-contact rule,
with
--writeand--allow-first-contactonadmin clients create. admin backfill, which asks the owner's phone for a chat's older history, with a quota.- Nightly encrypted backups at
WAWARDEN_BACKUP_TIME, with catch-up, retries and retention (WAWARDEN_BACKUP_KEEP), andbackup verify. - Audit retention (
WAWARDEN_AUDIT_RETENTION_DAYS) behind a signed audit anchor. - Master key rotation with
keys rotate, and retired keys inkeys/retired/. - The events
backup_pruned,backup_prune_failed,audit_key_changed,send_outcome_unknownandsend_unrecorded. - The compatibility promise, tested against
internal/archtest/testdata/v1-surface.txt. - The hardening guide, the ban-risk notes and the runbook.
Security¶
- Client and admin tokens are redacted from logs, events and command errors.
- The send path is confined: a send decides its write grant first, only the
sender writes
sent_by, andinternal/apicannot importinternal/sender. Sent rows carry the origingateway:<client id>. reply_tois sealed like a message reference, and each send has a fingerprint.- Outbound text is checked before it is sent, and a send to a direct chat that never wrote to the account is refused.
- Retired keys are used by
audit verifyand to open cursors, and a key change reportsaudit_key_changed. - The audit retention verifies the rows it removes before it signs the
anchor, and reports
audit_prune_refusedwhen they do not verify. - An audit row is written even when the client left before its answer.
- Startup refusals for
WAWARDEN_BACKUP_TIME,WAWARDEN_BACKUP_KEEP,keys/retired/,WAWARDEN_AUDIT_RETENTION_DAYS, the send limits andWAWARDEN_UNSAFE_SEND_CAPS. - Fuzzing of idempotency keys, outbound text and the send route.
Upgrade notes¶
- Releases before
v1.0.0recorded a backup only asbackup_taken_at. After an upgrade, that value counts as the newest successful backup for the nightly schedule. - Audit lines written before
v1.0.0carry nokey_id. While the audit anchor is under a retired key, the head of a removed row on such a line counts as missing inaudit verify --log(exit6). The next retention run makes the anchor again under the current key.
0.3.0 - 2026-10-11¶
Built from commit d2d2534 with go1.27.2.
Added¶
- Clients with per-chat read scopes and expiring tokens:
admin clients create,list,showandrevoke, andadmin chats list. - The read API over REST: chats, messages, search and a change feed, in pages with sealed cursors and message references.
- The same reads as MCP tools at
POST /mcp. - Per-client read and search budgets.
- Owner-saved contact names, shown only to a client that may read the contact's direct chat.
- The hash-chained audit chain, its chain heads on standard output, and
audit verify. - The scoped store, its single
INbuilder, uniform resolution and bounded reads, with property tests. - Golden files for the MCP
tools/listanswers. - The guide for agents.
Security¶
- Write chats are a subset of a client's read chats, and a client that reads every chat cannot write.
- Clients are kept in memory, and a revocation takes effect on the client's next request.
- Every read goes through the scoped store's grant-first methods, and read answers are built from dedicated response types only.
golang.org/x/textis confined to one package;pgregory.net/rapidis a test-only module; the cursor and rate-limit packages use the standard library only.- The MCP library is given no logger, and
serverefusesMCPGODEBUGandJSONSCHEMAGODEBUG. - The cursor and audit keys are derived from the master key, and audit lines carry chat HMACs instead of chat identifiers.
- The client create body is capped at 64 KiB, and the MCP endpoint checks a body before the MCP library reads it.
- Fuzzing of the remaining targets, among them the client token parser, the
full-text query builder, the
INbuilder, cursor and message-reference opening, and the read API's query parsing.
0.2.0 - 2026-10-06¶
Built from commit da456bf with go1.27.1.
Added¶
- The WhatsApp engine, through the protocol library
go.mau.fi/whatsmeow. - Pairing by code, guarded by an account check against
WAWARDEN_OWNER_PHONE. - History sync, under a size cap (
WAWARDEN_HISTORY_MAX_BYTES). - The device store and the message archive in SQLite, with verified settings and removal of revoked, edited and expired text from the disk.
admin status,admin pairandadmin reconnect.- Notification events on standard output and a signed webhook
(
WAWARDEN_NOTIFY_URL). - Metrics on standard output in embedded metric format (EMF)
(
WAWARDEN_METRICS_EMF). - One encrypted backup per paired device, to an age recipient
(
WAWARDEN_BACKUP_AGE_RECIPIENT). - The log writer's pseudonyms for WhatsApp identifiers, keyed by the master key.
- The strict chat identifier normaliser and the seal package for grants and chats.
- The fake engine for development builds (
WAWARDEN_DEV_FAKE_ENGINE).
Security¶
- A neutral engine core: only the protocol adapter imports the protocol library. A guard keeps every test off the network.
- Two reviewed module lists, standard-library-only packages, store and engine
import fences, and
os/execconfined to the token command. - One database handle; database files are created with mode
0600. - The master key in
keys/, the keys directory rule, and a log pseudonym key. - One log writer that drops lines carrying XML, the protocol-library log
adapter, and
WAWARDEN_UNSAFE_DEBUG. - One notifier; the webhook checks its destination and signs every delivery with a secret read from a file.
- The events
admin_auth_failureandadmin_mutation. - Pairing refusals, a strict JSON decoder for request bodies and a terminal sanitiser.
- Backups are encrypted to the age recipient only: the service holds nothing that decrypts one.
safegorecovers a panic in the adapter's event handler.- Fuzzing of
Normalize, also against the protocol library's parser, the sanitisers, JSON decoding and crafted protocol messages.
Changed¶
- The licence changed from MIT to
GPL-3.0-or-later, because the protocol library depends on a component licensed under GPL-3.0.v0.1.0stays under MIT (see Licence). - Release images follow the
container contract from this
release on: the distroless
nonrootbase, user65532,/data, the exec-form health check,/licensesand the image labels.
0.1.0 - 2026-10-04¶
Built from commit d0d5514 with go1.27.1. Released under the MIT licence.
Added¶
- Configuration checks and startup refusals, including the refusal of any
unknown
WAWARDEN_variable. - The client, admin and health listeners, on loopback by default.
- The admin token, configured by its SHA-256 only, and
admin init. - Prometheus metrics on the admin listener.
healthcheckandversion.- The policy core: read, write and admin grants from decision functions, and route registration that requires a policy class.
- The container image and verifiable, reproducible releases.
Security¶
- Requests from browsers (
Origin,Sec-Fetch-Site) andOPTIONSrequests are refused. Authentication runs before any body is read. - Fixed error bodies, HTTP timeouts, a 16 KiB header limit, and
Cache-Control: no-storeandnosniffon every answer. - Failed-authentication counters and a budget of 30 failures, refilled at one per second, on the client and admin listeners.
umask 077andGOTRACEBACK=singleare the first statements ofmain.- Startup refusals for a plaintext admin token, the admin hash's form and
sources,
WAWARDEN_DEV_*in release builds,GOTRACEBACK, the listen addresses, running as root, and the data directory's owner and mode. - Import fences, response types with a forbidden-key test,
safego.Go, the listener inventory and constant-time comparison. - Fuzzing of the admin token check.
- Release builds prove the
devbuild tag absent. The container image runs as a non-root user on a distroless base with a read-only root filesystem.