Before Heatrail, an Estonian online retailer wrote its report to the national CERT the way most shops do: by hand, afterwards, out of exports that had to be put back into order and a person's memory of the week. It took days. The same report is now assembled from a record that was already being written while the incident happened. This article is about that record, and about where it stops.
The property
Every consequential event is appended to a hash-chained ledger that is signed every night and verified against a key held outside the database. When a shop needs to go to the authorities, the technical file is generated from that record, and the memo is a draft a person reads, edits and sends. Minutes, not weeks.
Why it holds
The report that used to take days
This product comes from a shop, not from its checkout. It comes from the week afterwards, when somebody has to explain what happened to a person who was not there. That retailer had done it: order exports from one system, payment references from another, and the sequence of who noticed what reconstructed out of a mailbox. Days of work, and the weakest parts of the file were the parts a case turns on: the order in which things happened, and whether anything was touched afterwards.
What changes is the assembly. The facts are the same facts, and no record makes a weak case strong. The events were recorded as they happened, in order, with the order itself protected, so producing the file is an export rather than an investigation.
What the chain catches, and what the signature catches
Every consequential event, the checks that mattered, the labels, the operator actions, the scoring configuration changes, is appended to a ledger. Each row stores the SHA-256 of its canonicalised payload and a row hash over its sequence number, its event type, that payload hash and the previous row's hash, from a genesis of sixty-four zeroes. Appends serialise on a database advisory lock, so sequence numbers are contiguous and an insert made outside the application breaks the chain. The break is the tripwire.
A nightly command recomputes the chain from genesis and compares each row against its stored hashes. A flipped byte, a deleted row or an inserted row is reported at the first sequence number that disagrees, and the command exits non zero. That catches editing, but not rewriting, because someone who can rewrite one row can rewrite all of them and re-hash the chain forward into something consistent with itself.
So the head is anchored every night at 00:05 UTC with an Ed25519 signature, and the verification at 00:15 UTC checks that signature against the operator's configured public key rather than a key stored beside the anchor. A rewritten chain re-signed with an attacker's key does not pass, because the key it is checked against is not in the place the attacker reached.
Figure 1
What the database refuses
Detection is worth a great deal and it is not prevention, so there is a third layer. The deployed application connects with a database role that holds only INSERT and SELECT on the ledger, the audit log and the anchor table, with UPDATE, DELETE and TRUNCATE revoked. It was verified by connecting as that role and attempting the forbidden writes: permission denied, from the database rather than from our own code. The layer carries a date, 2 September 2026, so a reader can tell which entries it covers. Entries written before it are vouched for by the chain and its anchors.
The boundary of that claim is in the agreement in the same words. The revocations bind the role the application connects with at runtime. They do not bind the separate owner credential the hosting platform holds for schema changes, and that credential is kept out of every process that serves a request. Against anything that reaches it the guarantee is detection rather than prevention: the hash chain, the nightly signed anchors, and a record of the chain's length kept outside the database, so an emptied ledger cannot present itself as a young one nobody has anchored yet.
The memo, and where it stops
When a shop decides to take an incident to the authorities, the file is generated from the record: the sequence of what happened and when, the order references involved, the labels and who applied them at what time, and the ledger entries and hash prefixes that tie the narrative back to the chain it came out of. It carries identifiers and hashes, not raw contact details.
Then it stops. The memo is a draft. A person opens it, reads it, corrects what the machine got wrong, signs it and sends it under their own name. There is no integration with a police force, no connection to a CERT, no partner distribution list, nothing queued for delivery. It is not a policy of refraining from sending. There is no mechanism that could send. The one automatic notification the system has goes to the admin of the shop whose order the incident belongs to.
Figure 2
Verify it
Read the integrity section of the security page. It states the three layers with the date each one came into force, and it records what the scheduled verification reports in production: the ledger intact, verified against the signed anchor.
Then read section 5(3) of the data processing agreement. It carries the same date, the same statement that the privileges bind the role the application connects with, the same detection only protection for entries written before it, and the owner credential boundary: the platform holds a credential those privileges do not bind, and against it the chain relies on detection. Comparing the two documents is the check. They describe the control at the same strength, clause for clause.
Legal footing
The ledger is the evidence side of the accountability duty in Article 5(2), which asks for the ability to demonstrate compliance rather than to assert it. It is not the record of processing activities under Article 30, which is a register of categories, recipients, retention and measures, and is a separate document: an event log answers what happened, and Article 30 answers what we do. The memo is prepared on the shop's instructions as controller and supports the shop's own lawful disclosure to a competent authority, for example under Article 6(1)(c) or (f) as applicable to that shop. Heatrail OÜ does not disclose to authorities on its own initiative, and could not: there is no mechanism. Records held as evidence for an active incident rest on Article 17(3)(e), and article 11 explains when that hold is released.
Related
- Corroboration, the rule that network heat needs two independently owned shops, and the operator actions (approving a shop, deciding independence) that go into this record.
- Forgetting on schedule, on how a permanent integrity proof and a ninety day deletion window live in one system.
- Security, section 07, for the layers and the dates they came into force.