No Token Meant Any Token
Written later and filed to this date, as part of filling in every day of the year.
Two commits, twelve seconds apart, on an evening at the start of June. The first was to the bridge that drives my torrent client from the glasses: “open mode when no token is configured”. The second was to the bridge that captures notes and audio from them: “optional token (open mode)”. The reason was the same in both bodies. The launcher on the glasses had dropped its per-app token screen, the bridges were private to the home network, and an unset token had been read as “locked”, which answered every request with a refusal. From that evening it was read as “open”.
The torrent bridge’s old header had said why it was locked: it acts on a real torrent client, so fail closed. The new header said the operator had opted out of token configuration. Both were true. The check itself became one line in the handshake: if a token is configured, compare it; if not, skip the comparison. Written out, that is if (token && frame.token !== token), and the thing to notice is what the && does when the left side is empty. The check does not fail. It vanishes.
Seven weeks later, at the end of July, I asked for every public-facing listener on my two machines to be cut, on the theory that attackers with models of their own would find an exposed service faster than I would notice it. The audit that followed was done from a second host, not from the box, and it found the whole list: torrent add and delete, irrigation actuation behind nothing but a static confirm header, a transcription service, every media dashboard, and the two bridges, written up in the commit as “two bridges whose empty-token check accepted any token”. It also found the one hole nobody had meant to make, a permanent mapping the torrent client had asked the router for by itself.
Everything moved to loopback or the private network that evening, with the code default set so that a missing variable fails safe. At 21:42 the capture bridge got its fix: it refuses to start without a token, and both of its checks go through one constant-time compare that never matches an empty expected value, because a check that can be satisfied by nothing is not a check. Seven minutes later the rule went into the workspace charter. It was written that night with a “must” in it, and a compaction in September took the must out, which is the right direction for a rule to age. It now reads, in full:
An unset token fails closed.
The charter follows it with the shape never to write again, quoted, and the two things to do instead: compare with the platform’s constant-time primitive, and refuse to start when the secret is missing. A later pass in August put one shared gate in front of every service on the private network, written once and imported everywhere, with the same property stated in its commit: there is no branch where “no secret configured” means “allow”.
The best record of the bug is the test that had protected it. In June the capture bridge’s suite gained a case named “open mode (no token configured) authenticates any hello”, and it passed. In July the same case was renamed “an unconfigured token rejects every hello (no fail-open mode)”, its assertions inverted, and it passed again. The old name had described the vulnerability exactly, in the present tense, for seven weeks, as a feature.