Security

A password manager should be judged on what it is attacked by, so here is the list: twenty threats with an identifier each, forty-five controls that answer them, and five of the risks accepted and not fixed.

I cannot ask you to take any of it on trust. The repository is private while I prepare the first release, so you can read these claims and not the code behind them, and nobody outside the project has reviewed either. The last section on this page is about that, and it is the one I would read first.

20
threats in scope
6
declared out of scope
45
controls, each with the file that implements it
13
register entries citing a published CVE or advisory

What it is attacked by

Every threat the design answers carries a stable identifier, T1 to T20, and each document that answers some of them names which ones. Six more are declared out of scope, each with its reason, and that matters as much: a threat model that covers everything covers nothing.

Out of scope, and said so rather than left out: a computer that is already compromised and captures the keystrokes Kleidos types, because typing them is the entire product; an attacker who decaps the chip or injects faults, since there is no secure element and no tamper-evident case; power and electromagnetic side channels, for which I claim nothing; a firmware image tampered with before you ever flash it; choosing the wrong credential, or typing the right one into the wrong field, which the device cannot see.

Written down in docs/security/threat-model.md.

The six you arrive with

Each is a question in the words a reader actually uses, then the answer, and then, for five of the six, the part the answer does not cover. A control described without its edge is the kind of security claim this page exists not to make.

Somebody takes the device. How long do they have?

Four wrong PINs lock it for a while, seven lock it for longer, and the tenth erases the vault, every Bluetooth bond and every saved admin network, in that order, with the counter cleared last, once the vault is already gone. The count survives a power cut, because it is written before the PIN is checked rather than after: pulling the battery halfway through a guess still costs the guess.

What that does not cover

A four-digit PIN is ten thousand combinations, and four digits is the default. Six and eight digits are offered, and so is a passphrase on the boards with a keyboard or a touch screen. What makes a short PIN survivable is the lockout, not the PIN.

Threats: T2

docs/security/pin-and-bruteforce.md

Somebody desolders the flash and reads it. What do they get?

The vault, as ciphertext. Every vault file is AES-256-CBC with an HMAC-SHA256 tag over the ciphertext, and the tag is verified before anything is decrypted, so a wrong key and a tampered file get the same answer, which is refusal rather than garbage. The PIN goes through PBKDF2-SHA256 (175,000 iterations on the ESP32-S3 boards, 40,000 on the classic ones, each sized to about a two-second unlock) to a key that checks the unlock and unwraps the vault's own random key, and the keys the records are encrypted under come from that random key.

What that does not cover

On the open builds the settings store beside the vault is not encrypted, so the same copy also holds, in the clear, the Bluetooth bond keys (enough to decrypt a recording of what the device typed into a paired computer), the attempt counter, the audit log, the settings, and the admin network's password if you chose to keep one. And the vault's own encryption is all there is: somebody holding the flash image can try PINs offline as fast as their hardware allows, and the only things slowing them down are the iteration count and how long your PIN is. The hardened build encrypts the flash and the settings and mixes in a secret of the device's own, which makes an offline attempt need that exact chip: on the classic ESP32 boards a random value kept in the encrypted settings, which only that chip can decrypt, and on the ESP32-S3 boards a key inside the chip's fuses, burned by a step that exists now and that I have not run on a board yet.

Threats: T1, T3

docs/security/vault-encryption.md

Somebody records the Bluetooth traffic. Can they read the password?

The link is Bluetooth LE Secure Connections only (legacy pairing is refused outright). Every characteristic of the keyboard service requires an encrypted link with a sixteen-byte key before its handler is ever reached, and the reports, which carry the keystrokes, also require that link to be authenticated; with numeric comparison the only pairing accepted, an encrypted link is always an authenticated one. Each burst of keystrokes re-checks that the link is still encrypted, still authenticated and still bonded before it sends, and every notification inside the burst checks again. The device advertises under a private address that changes every fifteen minutes.

Threats: T6

docs/security/ble.md

Can something else pretend to be the computer I paired with?

Pairing is numeric comparison: six digits on the device's own screen, which you confirm by hand. A request to re-pair a bond that already exists is denied by default and needs confirming on the device, and a confirmation that times out counts as a refusal rather than as a yes.

What that does not cover

Evicting the oldest bond when the table is full asks the same way, and the table holds four. On the classic ESP32 boards the controller's accept list and the rotating private address cannot both be on: the stack refuses the list while the address is on, so those boards keep the address privacy and not the list.

Threats: T7, T8

docs/security/ble.md

The admin panel is a web server on a password manager. Really?

It runs only while you ask for it, on a WPA3-only access point with protected management frames and a maximum of one client. The access point's password is shown on your unlocked screen and, unless you choose to keep one, is drawn afresh for each session, surviving only the one restart an update causes so that your browser can rejoin. The page asks for a session token when it loads, from a route capped at thirty requests a minute from any one address. Every route it calls after that, except the one that uploads an update, carries the token, which is compared in constant time and expires after five idle minutes; the upload route takes the upload password instead, compared the same way. All of them share a cap of eighty requests a minute. Only the page itself, and the redirect that sends any other path to it, are served with no cap at all. Bluetooth and Wi-Fi never run at the same time: every Bluetooth session has one owner that stops it, and this page is reached only after that stop.

What that does not cover

Inside that network, the panel trusts whoever joined it. That is the design and not an oversight: one client, a network that exists for minutes, a password you read off the device. But it does mean you should scan the QR code on the device's screen yourself, and in private. And if you choose to keep one password for every session, whoever reads it once keeps it, and on the open builds it is stored unencrypted in the device's settings, where a copy of the flash gives it away.

Threats: T11, T12

docs/security/wifi-admin-portal.md

What happens when something it links has a CVE?

There is a register: thirteen of its entries cite a published CVE or advisory, and two answer a known flaw nobody has published one for. Each says whether Kleidos is affected and why, with a link to its public source. Of all those entries, eleven cite a line of this repository as the evidence; the other four rest on an argument instead: the compiler the fleet is built with, the cryptography the firmware uses, or what the flaw needs in order to fire. Three are marked accepted risk, all three in the Bluetooth stack the framework bundles. One is in the radio controller's link layer, below the host this code drives. The other two are in that host, in the code that reads what the controller sends it, and both need the controller to send something it should not: the controller is part of the chip, so an attacker over the radio would have to compromise it first. And one of the two can only crash the device, which restarts with no keystroke and no pairing at risk. All three close when the framework ships the fixed release of that stack.

What that does not cover

It is a register of what has been published and looked at, which is not a register of what is there. What the firmware links is named and pinned. ESP-IDF 6.0.3 (which brings the Bluetooth host and the Wi-Fi stack), mbedTLS 4.1.1 with TF-PSA-Crypto 1.1.1 and ArduinoJson 7.4.3 are pinned to the digit, and LittleFS is held at 1.22.1 by the committed lock files, since its manifest accepts any 1.x from 1.10.2. So a bump is a deliberate act rather than a drift, and that is the whole of the supply-chain story today.

Threats: T17

docs/security/cve-register.md

What answers them

One table maps each of the forty-five controls to the threat it mitigates, any advisory it addresses, the file that implements it, any standard it follows, and how to check it. Here they are grouped by what they protect.

The table is written for somebody auditing the device, which is why each row points at the code rather than describing it. It is the document I would hand to a reviewer, and it is the document nobody outside the project has read.

Written down in docs/security/audit-dossier.md.

What is accepted and not fixed

Here are five of the risks the design acknowledges and does not close; the threat model and the audit dossier list the others. The first is in effect today, and it is the one I would want to be told about if I were reading somebody else's page.

  1. A retired PIN still opens the current vault

    Changing the PIN re-wraps the vault key rather than minting a new one. So the old PIN, plus any copy of the vault's metadata file made before the change, recovers the key in use now, and with it every credential written since. That file can come off the flash. Or it can come out of a sealed backup made before the change, for someone who also has that backup's passphrase. The attack needs read access to the current ciphertext and no write access at all. The whole-vault re-encryption that does rotate the key is kept and offered as an explicit action, on the device and in the panel. Destroy or retake any backup made before you changed the PIN.

    Threats: T19

    docs/security/vault-encryption.md

  2. A whole-vault rollback cannot be detected on the open builds

    Each record carries a generation counter, so no single record can be put back on its own. Restoring the whole vault (the metadata and every record together) to an older consistent state passes every check, because the counters go back with it. On the hardened builds, encrypted flash and verified boot stop an attacker from forging such a state, but not from replaying one captured from that same device.

    Threats: T5

    docs/security/audit-dossier.md

  3. The PIN is short by default

    Four digits is ten thousand combinations. Six and eight are offered, and a passphrase on the boards where you can type one. What makes the short PIN survivable is the lockout and the erase, and both are online defenses: they do nothing against somebody who already has the flash.

    Threats: T2

    docs/security/pin-and-bruteforce.md

  4. The classic boards cannot have both kinds of Bluetooth privacy

    On a classic ESP32 the host-managed rotating address and the controller's accept list are mutually exclusive: the stack returns not-supported for the second. Those boards keep the rotating address; the ESP32-S3 boards have both.

    Threats: T6

    docs/security/ble.md

  5. Three boards have no hardened build at all

    The Plus 1.1, the Plus SE and the CoreInk carry 4 MB of flash, which does not hold two update slots and a signed bootloader. They rely on the vault encryption alone against a stolen flash, and they are updated by re-flashing them whole.

    Threats: T1, T16

    docs/security/flash-and-production.md

What you cannot check

Read this part before deciding anything.

If you want one sentence: this is one person's serious attempt at a hardware password manager, documented in detail and reviewed by nobody.