# Audit Trails: Not a data lake

> Built naively, an audit trail becomes the largest and least erasable store of personal data you own. How privacy principles and minimal disclosure shape a trail that proves without exposing.

Source: https://www.bluewise.fr/audit-trails-not-a-data-lake  
Author: Marc Morel  
Published: 2026-05-25  
Category: Architecture  
Series: Audit trails, part 2

In [Part 1](https://www.bluewise.fr/audit-trails-logs-are-not-enough), we looked at what turns a record into evidence: completeness, tamper-evidence, and time witnessed by someone other than yourself. I closed that post with a word of caution, and I'd like to pick up the thread right there.

Follow that advice to the letter and you may end up building something quietly dangerous: a store that covers every customer and every change, is kept for years, and is designed so that nothing in it can ever be modified or removed. In many organisations, it becomes the largest concentration of personal data they hold. A data-protection liability on one side, and a very attractive target for attackers on the other.

The reassuring part is that none of this is inevitable. An audit trail exists to **prove what happened**, not to keep a second copy of everything that was touched along the way. The discipline that keeps those two goals apart is *minimal disclosure*, and it applies at three moments in the life of a record: when it is written, as time passes, and when someone reads it.

Two questions sit right next to this one, and each deserves more than a paragraph: who is allowed to write the trail, and who is allowed to open it. They have their own articles later in the series. Here, we focus on what the trail contains and what it gives away.

## One artefact, two duties

Data protection law puts the audit trail in a rather unusual position. The GDPR's accountability principle asks an organisation to be able to **demonstrate** that it handles personal data properly, and the audit trail is very often its main piece of evidence. Yet the trail is itself a processing of personal data, bound by the very principles it helps to demonstrate.

Put simply, it has to prove compliance while complying.

Europe is far from alone here. The UK GDPR, Switzerland's revised Federal Act on Data Protection, Brazil's LGPD, California's CCPA as amended by the CPRA, Canada's PIPEDA, Japan's APPI, Singapore's PDPA and India's Digital Personal Data Protection Act each have their own vocabulary and nuances, but they rest on a similar family of ideas. A trail that honours those ideas travels well across jurisdictions.

The good news is that each principle translates into a concrete design control.

| Principle                          | What it means for an audit trail                                                                                                                  | Design control                                                                                   |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| Lawfulness, fairness, transparency | A documented legal basis (typically a legal obligation, or a legitimate interest in security and fraud prevention), and people who know they are logged, employees included | Basis recorded in the register of processing activities; staff informed that their access is logged |
| Purpose limitation                 | Data collected for accountability, security and fraud control is not quietly reused for performance monitoring or analytics                       | A declared purpose per stream; every query carries a purpose; no generic export                  |
| Data minimisation                  | Only what is needed to prove the event                                                                                                            | References, pseudonymous IDs and keyed hashes instead of payloads                                |
| Accuracy                           | Records reflect what happened; mistakes are corrected without rewriting history                                                                   | Corrections are compensating entries that point to the original, never edits                     |
| Storage limitation                 | Kept as long as an obligation requires, not forever                                                                                               | Retention defined per stream; crypto-shredding at expiry                                         |
| Integrity and confidentiality      | Protected against tampering and unauthorised access                                                                                               | The tamper-evidence from Part 1, plus governed access                                            |
| Accountability                     | The organisation can demonstrate compliance                                                                                                       | The trail evidences the business processing, and its own compliance                              |

The GDPR also asks for privacy **by design and by default**. These controls belong in the first version of the architecture, not in the remediation plan that follows the first audit finding. Three of them are where engineering teams most often stumble, and they are the ones I'd like to walk through with you: minimisation, storage limitation, and confidentiality at read time.

## Write less: references, not payloads

Minimisation at write time begins with a simple question: what is the least this record must contain to prove the event later? The honest answer is usually much less than the payload the service happens to have in hand at that moment.

| Record this                                      | Not this                                        | Why                                                                   |
| ------------------------------------------------ | ----------------------------------------------- | --------------------------------------------------------------------- |
| Pseudonymous subject ID                          | Name, email, phone                              | Links the event to the subject without identifying them in the trail  |
| Names of the fields changed                      | Full before/after payloads                      | Shows what was modified, not the content                              |
| Keyed hash (HMAC) of before/after values         | Clear-text values                               | A disputed value can be verified later without ever being stored      |
| Encrypted field, when content is truly required  | Clear-text sensitive data                       | Readable only by the authorised few, and erasable later               |
| Actor identity, case ID, purpose code            | Free-text justification with customer details   | Accountability without leaking the investigation                      |

To make this concrete, here is what a minimal event for a change of payment beneficiary might look like:

```json
{
  "seq": 1048213,
  "prev": "sha256:9f1c…",
  "at": "2026-07-14T14:02:11.482Z",
  "actor": { "type": "human", "id": "emp-7Q2K", "auth": "fido2" },
  "action": "beneficiary.update",
  "subject": "cust-p:8d41a7",
  "object": "acct-p:1f0c93",
  "fields": ["iban", "holder_name"],
  "before": "hmac:3a7e…",
  "after": "hmac:c019…",
  "purpose": "customer-request",
  "sig": "ed25519:…"
}
```

It tells us who changed which beneficiary, when, how the actor authenticated, and for what purpose. It contains no IBAN and no name. Should the change ever be disputed, the original values can be checked against the keyed hashes, without the trail having stored them.

Notice also that `purpose` is a code from a controlled list, not a sentence. Free-text fields are where personal data sneaks back in. A well-meaning agent typing *"Mrs Martin called, she is moving to Lyon next month"* can undo, in a single line, all the care that went into the rest of the schema.

### A hash is not a disguise

A plain SHA-256 of an IBAN or a date of birth protects far less than it seems to. These values have low entropy, so an attacker can simply hash every plausible candidate and look for a match. A keyed hash (HMAC), whose key lives in a separate key management system, closes that door: the audit store on its own can no longer be reversed.

It is worth being clear about what this buys, legally. Pseudonymous IDs and keyed hashes are **pseudonymisation**, not anonymisation. The data remains personal data, because it can be re-linked by whoever holds the key. That is still very much worth doing, since the GDPR explicitly names pseudonymisation and encryption among the security measures it expects. It simply does not take the trail out of scope.

## Let time do its work: immutability versus erasure

An append-only, tamper-evident log and the right to erasure look irreconcilable at first sight. In practice, three mechanisms resolve most of the tension.

**1. Legal retention comes first.** Where records must be kept to meet a legal obligation, anti-money-laundering record keeping being the classic example, the right to erasure gives way for as long as that obligation runs. Immutability during the retention period is therefore lawful. The obligation does need to be named, stream by stream, with its own duration and its own starting point (end of the customer relationship, date of the transaction, closure of a case). "We keep everything for ten years, just in case" is not a retention policy; it is the absence of one.

**2. Storage limitation is enforced with keys, not deletes.** Personal data in the trail is encrypted under per-subject keys held in a KMS or HSM, outside the audit store. When retention ends, the key is destroyed. The ciphertext stays exactly where it is, and the hash chain remains valid because it was computed over the ciphertext, but the content is now permanently unreadable. This is crypto-shredding.

**3. Pseudonyms are unlinked the same way.** The table mapping pseudonymous IDs to real customers lives outside the trail. Delete a subject's entry in that table, destroy the HMAC key used for their values, and their events become effectively anonymous while remaining verifiable as a sequence. Disputed values can no longer be checked either, which is precisely the point: any dispute window should sit comfortably inside the retention period.

Crypto-shredding has a lovely side effect that is often overlooked: it also reaches **backups and replicas**. Every copy of the trail, wherever it sits, becomes unreadable for that subject the moment the key is gone. Deleting records one by one across WORM storage, replicas and archives would have been impossible anyway.

There is, of course, a price, and it is key management. Per-subject keys mean millions of keys, a hierarchy in which they are wrapped by a handful of master keys in the HSM, and a key-destruction process governed as rigorously as any privileged access. An accidental key loss is just as irreversible as a deliberate shred. It is also wise to agree with your DPO and legal team on how crypto-shredding is described in your records of processing: the mechanism is sound, and the wording is what auditors will read.

## Show less: minimal disclosure at read time

Minimising what is written is half the job. The other half is minimising what each reader sees. Being allowed to open the trail does not mean being entitled to all of it.

### Masked by default, revealed on demand

Every view starts masked: pseudonyms, keyed hashes, field names, no clear values. When a case genuinely requires it, the reader reveals **one field of one record**, stating the case and the reason. The value is decrypted just in time, and the reveal itself is written to the trail.

Disclosure becomes progressive, deliberate and traceable, the very opposite of a full dump on the first query. It also gives reviewers a precise signal: someone who reveals four hundred fields on a case scoped to a single customer stands out immediately.

### Purpose-bound queries

The query interface simply refuses any request that does not carry a purpose. Each purpose maps to a scope: an investigation opens one subject's events for a defined period; an internal audit sample opens a random set of events with actors visible and subjects masked. There is no "select everything" endpoint, and exports are watermarked, time-limited and recorded.

Who may open the trail in the first place, how that access is requested, approved and time-boxed, and what happens in an emergency, is a governance question in its own right.

### When the data subject asks

In `Pankki S (C-579/21)`, decided in June 2023, the Court of Justice of the EU looked at exactly this situation. A bank employee, who was also a customer of that bank, asked who had consulted his customer data, when and why. The Court held that his right of access covered the **dates and purposes** of those consultations. The identity of the employees involved is, in principle, not owed, unless it is essential for him to exercise his rights effectively, and only after weighing the employees' own rights.

The engineering consequence is direct. If your trail does not record the purpose of each read, you cannot answer a lawful access request. If it cannot separate actors from access metadata, you cannot answer without over-disclosing your own colleagues. Minimal disclosure, then, is not only a restriction placed on readers; it is a capability you have to build in order to meet your obligations.

One nuance deserves care. National law may restrict access rights in specific situations, for instance during an anti-money-laundering investigation, where tipping off the subject is an offence in its own right. The trail should let the data protection officer apply such restrictions case by case, rather than forcing a choice between everything and nothing.

## What changes

A well-designed audit trail proves who did what, when and why, without becoming a second copy of the data it protects. Minimise at write time with references and keyed hashes. Enforce storage limitation with keys rather than deletes. Disclose at read time one field, one purpose and one case at a time.

If you would like a starting point for your next design review, these questions tend to surface the gaps quickly:

- Could any field in our events identify a customer without a key held somewhere else?
- Is there a free-text field anywhere in the schema?
- For each stream, can we name the obligation that justifies its retention, and for how long?
- If a subject's key were destroyed today, would every replica and backup follow?
- Can we answer an access request with dates and purposes, without exposing our own staff?
- Is there any query path that does not require a purpose?

Done this way, the audit trail stops being the data lake nobody dares to touch. It becomes exactly what the accountability principle asks for: calm, verifiable evidence that the organisation handles personal data the way it says it does.

We now hold two of the ingredients: the evidential properties of Part 1 and the disclosure discipline of this post. Before assembling them, one question remains: who actually writes the records? [Part 3](https://www.bluewise.fr/audit-trails-who-writes-them) turns separation of duties onto the evidence itself.
