Chain of Custody

Hash-linked custody event model and verification method.

Entry structure

Each custody entry in the custody_entries table contains:

  • id: UUIDv4 generated at insert time.
  • file_id: Foreign key to the evidence file.
  • action: One of intake, transfer, processing, review, export, seal, release .
  • to_party: The custodian or system stage now responsible (e.g., pipeline:hash , system:export ).
  • file_sha256: The SHA-256 of the file at the time of entry.
  • prev_entry_hash: The entry_hash of the immediately preceding custody entry for this file.
  • entry_hash: SHA-256 of the canonicalized entry payload: id | file_id | action | to_party | file_sha256 | prev_entry_hash | created_at .

Verification method

Any user with access to a file can verify the custody chain:

  1. Fetch all custody_entries rows ordered by created_at for the file.
  2. For the first entry, confirm prev_entry_hash is null. Recompute entry_hash from the returned fields and compare.
  3. For each subsequent entry, confirm its prev_entry_hash matches the previous row's entry_hash . Recompute and compare.
  4. If any recomputed hash differs, or if the prev-link is broken, the chain is invalid.

This verification is implemented in server/lib/custody.js and exposed in the document viewer sidebar under the Custody tab.

Limitations

  • Custody entries are created by the Evident ICU server. If the server is compromised before an entry is written, the gap is detectable only if the user has an independent copy of the file hash from intake.
  • The chain proves sequence and integrity of server-recorded events. It does not prove the content of the original file is true — only that the file has not changed since intake.
  • External transfer events (e.g., sending a DVD to opposing counsel) must be recorded manually or via the API by the user. The platform cannot detect physical handoffs it does not observe.

Inspect a live custody chain in the viewer.