# Verify a hash chain

Kind

tutorial

For

developer · operator · governance

Verified against

@veritio/core@0.4.7

Start with the two intact records from [Record your first audit event](/docs/start/record-first-event/). This exercise changes a copied record and removes another one; it never mutates the store.

## Run the failure exercise

[Section titled “Run the failure exercise”](#run-the-failure-exercise)

src/examples/tutorial/tamper.ts

```ts
import { verifyAuditRecords } from '@veritio/core'
import { recordTutorialChain } from './record-and-verify'

const records = await recordTutorialChain()
const changed = records.map((record, index) =>
  index === 1
    ? { ...record, event: { ...record.event, metadata: { ...record.event.metadata, role: 'admin' } } }
    : record,
)
const dropped = records.slice(1)

console.log(JSON.stringify({
  changedRecord: verifyAuditRecords(changed),
  droppedRecord: verifyAuditRecords(dropped),
}, null, 2))
```

Terminal window

```sh
bun src/examples/tutorial/tamper.ts
```

The checked fixture prints:

verified output

```json
{
  "changedRecord": {
    "ok": false,
    "index": 1,
    "reason": "hash_mismatch"
  },
  "droppedRecord": {
    "ok": false,
    "index": 0,
    "reason": "sequence_mismatch"
  }
}
```

## Tampering detected

[Section titled “Tampering detected”](#tampering-detected)

The first result changes `metadata.role` from `viewer` to `admin` without recomputing the stored record hash. Verification stops at array index `1` with `hash_mismatch` because the current canonical record bytes no longer produce the stored hash.

This is not a warning. A consumer must treat the record set as unverified and investigate the source, transport, or storage boundary that supplied it.

## Dropped record detected

[Section titled “Dropped record detected”](#dropped-record-detected)

The second result removes sequence `1`. The remaining record still says it is sequence `2`, so verification stops at array index `0` with `sequence_mismatch`.

Removing a record from the middle of a longer chain can instead surface a sequence or previous-hash mismatch at the next surviving record. The first returned failure identifies the earliest inconsistency the verifier can prove.

## Checks performed in order

[Section titled “Checks performed in order”](#checks-performed-in-order)

For each ordered record, the verifier checks the supported algorithms and canonicalization label, tenant scope, expected gapless sequence, expected previous hash, and recomputed record hash. It returns `{ ok: true }` only when every supplied record passes.

Verify the right artifact

A filtered list is not automatically a complete chain. Use an export whose manifest declares its chain scope when you intentionally verify a subset. Never turn a failed result into warning-only success.

## What verification cannot prove

[Section titled “What verification cannot prove”](#what-verification-cannot-prove)

Integrity verification proves consistency of the supplied record bytes and links. It cannot prove that the application reported a truthful real-world event, that the actor was authorized, or that an omitted chain was never created elsewhere. Those remain application, identity, and operational trust questions.

Continue with the [byte-level hash-chain explanation](/docs/concepts/hash-chain/) or use the [verifier error reference](/docs/reference/verifier/).

[Edit page](https://github.com/getveritio/veritio-website/edit/main/src/content/docs/docs/start/verify-a-chain.mdx)

Last updated: Aug 23, 2026

[Previous  
Record your first event](/docs/start/record-first-event/)[Next  
Choose your path](/docs/start/choose-your-path/)

Veritio provides evidence support, not legal advice or automatic compliance.

This site uses cookieless, anonymous analytics (Umami) by default. With your consent, we also enable Google Analytics, which sets cookies and sends usage data to Google. [Privacy Policy](/legal/privacy/)
