SECOND MEASUREMENT SM-004
We tried to catch whisper.online's ledger out. It passed every test, and we found it sending us ten copies of everything
whisper.online runs a public ledger meant to prove nothing in it is ever quietly changed. We checked it the hard way, with our own code instead of theirs: inclusion proofs fold to the signed root, history proofs hold, malformed requests get refused. Everything passed. Along the way we noticed their system was sending our witness about ten copies of every update, 16,180 a day. They fixed it: one copy each, 1,698 a day.
- We checked whisper.online’s public ledger with our own code, written from the standard, not theirs.
- 3 of 3 inclusion proofs and a history proof fold to the signed root, and the signature verifies.
- 4 of 4 malformed requests are refused.
- Their system was sending our witness about ten copies of each update: 16,180 a day.
- After their fix: one copy each, 1,698 a day. The operator reproduced our checks.
Round trip. The operator replied, fixed what we measured, and the recheck confirmed it. The seal is theirs; it links here and to the log leaf that pins this page.
Disclosure: Markovian Protocol holds no financial position in any organisation named here, was paid by no one for this work, and showed it to no one before publication except the organisation measured. How we work.
whisper.online runs a public ledger that only ever grows, and says anyone can verify it with two basic tools, curl and Python. We checked four of its claims using our own code, written from the published standard (RFC 6962), not their scripts.
On 30 September, three entries we picked were provably in the ledger, and an older version of the ledger was provably the start of the current one. Both proofs match the signed latest state (388,768 entries), and the signature checks out against their published key. Four badly formed requests to the page that proves older versions are now refused. Before a fix in September, that page answered them anyway.
Their system also sends updates to witnesses like ours. Before a fix on 21 September it sent us 16,180 a day, about 10 per real change. After it, 1,698 a day, one per change, an 89.5% drop. They had estimated about 1,200 a day and have since agreed with our figure. Their retired first ledger's final state, and the Bitcoin timestamp we made for it, are served byte for byte the same as the copies our witness keeps.
What they said, what we found
| They said | We found |
|---|---|
| Anyone can verify the ledger with curl and python3, using its /inclusion and /consistency pages.1 | True. Our own code, written from the standard rather than theirs, checked 3 entries and 1 history proof against the signed state. All matched. |
| Ask the consistency page a question and it answers it. | Until 17 September it also answered questions you didn't ask: requests with misspelled parameters got an answer instead of an error. Now all four we tried are refused. |
| After their fix, about 1,200 updates a day reach each witness, down 93%. | Our witness counted 1,698 a day, down 89.5%. They checked and agreed. |
| The retired ledger's final state and its Bitcoin timestamp are served under /ledger/g1/. | Byte for byte identical to the copies our witness keeps. |
The proofs
A ledger like this makes two promises you can check with math. Inclusion: this entry is in the ledger. Consistency: today's ledger starts with exactly yesterday's, nothing rewritten. We wrote our own checker from the standard, RFC 6962,2 instead of using their scripts.
We picked three entries: the very first (0), the example on their verify page (166), and the last entry at our first look on 12 September (282,775, when the ledger held 282,776). For consistency we went from 251,620, the size in their example, to today's size. We also checked the signature on the latest state against the key our witness pins, whisper.online/ledger/g2+d40e573a.
| Check | Ledger size | Root | Result |
|---|---|---|---|
| Entry 0 is in | 388,768 | LofFPbFiG/PYWZOl2L8jh3nbzwRRbcZvtXhR1rUzJB8= | matches |
| Entry 166 is in | 388,768 | same | matches |
| Entry 282,775 is in | 388,768 | same | matches |
| 251,620 is the start of 388,768 | 388,768 | same | matches |
| Signature, key d40e573a | 388,768 | valid |
30 September 2026. The consistency proof also gives the root at size 251,620, CHzINved7GUCq9pkgMgijPiZMynd6OX+hgRmLxYZvbY=, which anyone who saved that state can compare.
The typo test
If you ask a checker for the wrong thing by mistake, it should tell you, not quietly answer a different question. We sent the consistency page four broken requests: from=100&tp=200, old=100&new=200, first=100&second=200 and bogus=1. All four get 400, refused. Before 17 September the page answered requests with unknown parameter names instead of refusing them. The operator reproduced that and changed it.5
Ten copies of everything
The ledger sends each new state to witnesses, including ours, which checks it and cosigns it.4 Our witness keeps every one it cosigns, so we counted them per day.
| Day (UTC) | Received | New sizes | Per size |
|---|---|---|---|
| 16 Sep | 16,163 | 1,667 | 9.70 |
| 17 Sep | 15,800 | 1,704 | 9.27 |
| 18 Sep | 15,875 | 1,635 | 9.71 |
| 19 Sep | 16,549 | 1,680 | 9.85 |
| 20 Sep | 16,511 | 1,711 | 9.65 |
| 21 Sep (fix) | 11,340 | 1,675 | 6.77 |
| 22 Sep | 1,503 | 1,480 | 1.02 |
| 23 Sep | 1,714 | 1,711 | 1.00 |
| 24 Sep | 1,722 | 1,721 | 1.00 |
| 25 Sep | 1,713 | 1,710 | 1.00 |
| 26 Sep | 1,741 | 1,737 | 1.00 |
| 27 Sep | 1,767 | 1,767 | 1.00 |
| 28 Sep | 1,634 | 1,634 | 1.00 |
| 29 Sep | 1,793 | 1,791 | 1.00 |
States of whisper.online/ledger/g2 received and cosigned by the Markovian witness.
Before the fix, their sender re-sent each state about every 5.4 seconds until the ledger grew: roughly ten copies of everything. After it, one send per new size. The operator described the fix as sending only when the ledger changes, plus a heartbeat every five minutes or so,5 and the data matches.
Their estimate of about 1,200 a day came from five sends in the first six minutes after the fix, scaled up to a day. But the ledger grows by about 1,700 sizes a day and every one gets sent, so the heartbeat never fires and the growth rate sets the volume. These are our witness's numbers; other witnesses may see different ones.
The retired ledger
whisper.online retired its first ledger, g1, at 18,994 entries, and now serves g1's final state and a Bitcoin timestamp for it under /ledger/g1/. The state is byte for byte the one our witness cosigned on 23 July. The timestamp is byte for byte the 1,669-byte proof we sent them on 22 September, which ties that state to Bitcoin block 968,085. We replayed it all the way to that block.
One leftover: those 471 bytes carry our witness's signature twice, at 11:59:40 and 11:59:45 UTC. That's the ten-copies bug, caught in July. It's now inside the hash that Bitcoin block 968,085 commits to, so it stays there for good. The newer ledger, g2, carries one signature per witness. g1's full tree is gone, so nobody can check an entry against g1 any more.
What they said back
The operator read a draft on 30 September and reproduced the typo test and the g1 checks from their side. On the volume estimate they wrote:5
your five full days of distinct sizes, 1,635 to 1,711, are what actually governs it. The growth rate sets the volume, exactly as you put it, the heartbeat never fires, and my 93 percent should read 89.5.
They also spotted the double signature in g1.
The evidence
Fetched 2026-10-02T18:10:28Z from the operator’s public endpoints. Copies and SHA-256 hashes: SHA256SUMS.
Exhibit 1 · The ledger today, signed by whisper.online and by our witness
whisper.online/ledger/g2 399981 q3KjGf77Hm4bbGfaIPOSXyvsSshvOLD8EysCzJhxOkc= — whisper.online/ledger/g2 1A5XOspUjjeXmkC3Teyv1MwHQCXyKju/kiMYc+YzB+yyAMJ10OePyzCVknRlK9tCks0SHRIffGIrL8rPAtaRSictYQ0= — markovianprotocol.com/witness QbiCfwAAAABqv/OTAYozG033sIm1SZ40DzLZGS46dWSZfQj5b63xFpVZPoDUKCN0km2dzdAz2Cyb3qMS2BS/RuEJu8PEmfOilrCaAw==
One signature from the operator, one from our witness. It is still the only independent signature on the ledger.
whisper.online/ledger/g2/checkpoint · raw g2-checkpoint.txt
Exhibit 2 · A malformed request, refused
GET /consistency?old=100&new=200
HTTP 400
{"error":"bad_request","detail":"unknown parameter \"old\"; this endpoint accepts only from and to"}whisper.online/consistency · raw consistency-bad-params.txt
Exhibit 3 · The retired first ledger, unchanged
whisper.online/ledger/g1/checkpoint 471 bytes, sha256 6cbd60ee…
The same bytes our witness kept, and the same bytes our Bitcoin timestamp commits to.
whisper.online/ledger/g1/checkpoint · raw g1-checkpoint.txt
Exhibit 4 · The operator, confirming the fix and the stakes
“On the 1,200 a day you are right and I was wrong, and the way I was wrong is the part worth recording.”
“You are the only reason that count is one and not zero.”
Kaveh Ranjbar (whisper.online), email reply, 30 September 2026, quoted with permission.
Disclosure timeline
| 17 Sep, 21:12 | We report that g1’s final head is unserved anywhere, so an old receipt fails closed instead of verifying. |
| 17 Sep, 22:34 | Kaveh Ranjbar confirms it from his side and commits to a fix, same evening. |
| 18 Sep, 01:16 | Live: g1’s head and key republished, g2 given its own origin path — and a second, worse bug he found himself while reproducing the fix (a missing parameter silently defaulting to the head) is disclosed and fixed in the same message, unprompted. |
| 18 Sep, 23:08 | We report the duplicate sends: 46,801 submissions over 4,880 sizes since 15 September, about ten per size. |
| 21 Sep | Kaveh Ranjbar fixes the duplicate-update bug we measured. |
| 30 Sep | Draft sent to Kaveh Ranjbar. |
| 30 Sep | He reproduces our checks and confirms them. Published. |
| 3 Oct | Round-trip seal given. |
What we can't be sure of
- Right now each g2 state carries one witness signature: ours. The operator reports four registered witnesses and a threshold of two. Until a second independent witness signs, nobody would catch it if the ledger showed someone else a different version.
- We checked three entries and one history proof out of 388,768. That shows the pages answer those requests correctly. It doesn't show the ledger never showed anyone a different version; only more witnesses can cover that.
- The volume numbers come from our witness's own database, which only we can read. We publish the table so Kaveh can compare it with his own logs.
Run it yourself
The scripts are also on GitHub: github.com/MarkovianProtocol/second-measurements/sm-004.
python3 check.py # the proofs and the typo test (needs network) python3 verify_note.py # checkpoint signature (needs the cryptography package) python3 distributor_daily.py # daily counts (runs on the witness host)
7d65e89a7c21c3b18f6d5b23f620537539afe4ed33e1498228fcc30ea889c851 check.py b1b9f7a3b653a18a18e112b0e97ae09b7a4671170c7f3cf0a495dced2316334d verify_note.py 6e1721596373cb2fd48dc37a4e66ba2b5591b153e5523d61d32971dfe673050f distributor_daily.py
Reproduced from the public repository on 3 October 2026 on a clean machine: holds at tree size 402,935 (three inclusion proofs fold to the served root, consistency from 251,620 verifies, four malformed requests get 400, the log signature verifies). Full table on the track record.
What you can do with this
- If you run a transparency ledger, serve a retired tree's final head under a stable URL; a receipt that can't be checked fails closed.
- If you push checkpoints to witnesses, submit on change, not on a timer; ten copies per size was the symptom here.
References
- whisper.online. Verify. whisper.online/verify. Accessed 2026-09-30.
- B. Laurie, A. Langley, E. Kasper. Certificate Transparency. RFC 6962, 2013. rfc-editor.org/rfc/rfc6962.
- C2SP. tlog-checkpoint and signed-note. c2sp.org/tlog-checkpoint.
- Markovian Protocol. Witness. witness.markovianprotocol.com/about.
- Operator of whisper.online. Personal communication by email, 2026-09-17, 2026-09-23 and 2026-09-30. Cited with permission.
Cite as
@misc{markovian-sm004,
author = {{Markovian Protocol}},
title = {Four checks of the whisper.online ledger},
number = {SM-004},
doi = {10.5281/zenodo.23071390},
year = {2026},
month = sep,
url = {https://markovianprotocol.com/measurements/sm-004.html}
}