KKleo

Kleo's threat model

What Kleo proves, what it merely claims, and what it leaks. Every promise on the website should be checkable against this document; where the two disagree, this one is right, and the website is a bug.

NETWORK.md describes the machinery this document judges: who talks to whom, what is signed, and what each message looks like on the wire.

What Kleo is

A desktop client for the plain-bitnames sidechain. Kleo holds no keys and performs no cryptography of its own: your node's wallet signs, encrypts and decrypts, and Kleo decides what to ask it and how to report the answer. So the security of anything here rests on three things — your node, your machine, and the chain — in that order.

Who you are trusting

You trustFor whatIf it is dishonest
Your nodethe chain's contents, your keys, every signature checkeverything below fails; a lying node can report any key it likes as someone's. Run it yourself, on loopback.
Your machinethe vault key in the OS keychain, plaintext on screenanyone with your unlocked machine reads every conversation. Kleo has no second lock (see gaps).
plain-bitnamesEd25519, ECIES over X25519, the consensus rulesout of Kleo's hands; Kleo adds no cryptography of its own.
The chain's minersthat a name's published keys are the owner'sa reorg or censorship attack on the sidechain could withhold or reorder key changes.

You do not have to trust a hub, a resolver, a relay, or anybody who forwards a message. That is the whole design, and the rest of this document is about how far it actually goes.

What is proved

via your node and checks the signature over exactly the message text. A key that no longer matches is reported as a mismatch, never as a pass.

that name publishes on-chain, with the node performing ECIES.

profile's canonical JSON. Kleo re-hashes whatever a server returns and compares. A host can withhold or serve a stale copy; it cannot alter one.

signed by the endpoint key they describe, and checked on the way out.

key; collecting it is signed by the recipient's, over a statement carrying the time, so a captured request goes stale.

address holding the recipient's name, with the message in its memo. The chain is the receipt.

author and the time, so it cannot be moved, re-attributed or edited.

to each member's BitName.

derived, used and dropped, so neither side's stored state opens what came before it — and the recipient's BitName key opens none of it at all.

the password and the block's own salt; XChaCha20-Poly1305 encrypts the text, so an altered block fails to open rather than opening wrongly. Nothing about it is published and nothing about it involves a name.

What is only claimed

is whoever registered it. Kleo pins the keys of saved contacts and flags changes, but it cannot tell you that a name belongs to the human you have in mind — confirm that the way you would confirm a phone number.

Nothing tells you it has: a missing message looks like no message.

payment and never reply. The payment proves you paid, not that you were heard.

words, not that the words are true.

not the armor it verified, so an export is a record, not a proof.

the chain holds, including names nobody has claimed in public and rows Kleo cannot put words to. A row is a registration, and nothing more.

What leaks

carries a connection, and any profile host you fetch from. Kleo does not bundle Tor or a proxy.

sent bob something, when, and how big. A direct connection tells the other side your address. Today chat also leans on iroh's default discovery and relays, which are Number Zero's servers unless you configure your own (Settings → Chat hubs).

chain; only its memo is encrypted. Amounts and timing are public forever.

unless you use a shared hub, which is why Kleo asks the configured one first.

(for broadcast and community channels) exactly what.

Kleo, hubs and anyone you talk to plainly see the names you use.

What Kleo downloads

Kleo can fetch a BitNames node for you, which means downloading a program and running it. What that rests on, stated plainly:

and no signatures, so Kleo carries the SHA-256 of the exact build it was tested against, verifies the bytes in memory, and only then writes them — to a temporary name inside Kleo's own data directory, made executable and renamed into place. A mismatch installs nothing.

fetching whatever is newest would mean running a binary nobody here has run and whose hash nobody has checked.

build it expected, not that the build is honest. A compromised release would be a compromised node, and a node holds your wallet.

grpc.kleoapp.xyz unless told otherwise. Whoever serves it can lie about Bitcoin — deposits, withdrawal bundles — and can never sign anything, read a message, or touch a name.

and sealed envelopes and can read neither, which is why it runs in-process with no extra install and why other people checking it against the chain lose nothing by using it.

Known gaps

These are real, and none of them is hidden behind a setting:

  1. Forward secrecy only where there is a prekey. A conversation between two names

that publish a chat.prekey runs a Double Ratchet: each message has its own key, so obtaining a BitName key later opens nothing that was already said. Everything else — a name with no prekey, the workbench, files, paid messages, channel posts — is still encrypted to a long-lived key, and someone who obtains that key and kept the ciphertext can read it. The ratchet is Kleo's own implementation of a well-known design, not an audited library.

  1. A lock is optional, and off by default. Without one, the vault key lives in the

OS keychain and Kleo opens whenever the machine is unlocked. With one (Settings → Lock), that key is wrapped under a passphrase and taken out of the keychain, and locking forgets the key and everything read with it rather than hiding it — so a locked Kleo holds no more than a closed one. What it does not protect: anything already on screen, and a machine compromised while Kleo is open. A backup file is protected the same way, and is only as strong as its passphrase.

  1. Deleting is local. Deleting a conversation clears your copy. It does not reach

the other side, a hub, or a chain — and a paid message is on-chain permanently.

  1. Metadata is not defended. No cover traffic, no mixing, no padding. Sizes and

timings are what they are.

  1. A malicious node is fatal. Kleo's checks are only as honest as the node answering

them. Remote nodes are supported for convenience, not safety.

  1. Unsigned builds. Until releases are signed and reproducible, a binary you did not

build yourself is a binary you are trusting someone about.

  1. Blocking is local. A blocked name is never told, and nothing stops them sending;

Kleo drops what arrives, after decrypting it.

  1. Attachments are written to disk. Files arriving in a conversation are saved under

Kleo's data directory in the clear, so whoever can read your disk can read them.

  1. A password is as weak as it is. A password-encrypted message is protected by

Argon2id at interactive settings and nothing else — no name, no chain, no second factor. A guessable password is a readable message, and sharing it with one more person is sharing the message with them.

  1. Activity shows public chain data, including other people's. Paid messages are

payments carrying a memo, so the chain shows that one went by and what it was worth to anyone who looks. Kleo reads none of them it cannot open, but it does not hide that they exist — the chain does not.

  1. The record of changes is partial, and local. Kleo notices a key rotation or a

new price only by comparing readings, so anything that changed while it was closed is missing, and two changes between two readings look like one. The file holds every name rather than a selection, so it says nothing about who you talk to — but it does record when Kleo was watching, in the clear, in your data directory.

Reporting something

If you find a problem with any claim above, please report it as an issue describing the class of problem. Kleo is pre-release: there is no reward programme and no coordinated disclosure process yet.