Skip to main content
drupalreleases
Release: Cms 2.2.3 — Update released for Drupal core (2.2.3)! Release: Easy Breadcrumb 2.0.11 — Minor update available for module easy_breadcrumb (2.0.11). Release: Bootstrap 8.x-3.42 — Minor update available for theme bootstrap (8.x-3.42). Release: Search API attachments 10.0.13 — Minor update available for module search_api_attachments (10.0.13). Release: Editoria11y Accessibility Checker 3.0.10 — Minor update available for module editoria11y (3.0.10). Release: Editoria11y Accessibility Checker 2.2.24 — Minor update available for module editoria11y (2.2.24). Release: Mismatched entity and/or field definitions 1.2.1 — Minor update available for module meaofd (1.2.1). Release: Lupus Custom Elements Renderer 2.8.1 — Minor update available for module lupus_ce_renderer (2.8.1). Module Revived: Bootstrap 8.x-3.41 — Theme bootstrap updated after 6 months of inactivity (8.x-3.41). Security Coverage: Component Library — Module component_library now has official Drupal security advisory coverage.

Audit Trail

3 sites Security covered

Part of the Audit ecosystem · 7 projects

View on drupal.org

This project adds tamper-evident logging to Drupal by creating a cryptographic chain of log entries. It ensures that any attempt to alter, delete, or insert records in the log can be detected, making it suitable for audit-worthy applications. The system uses a two-tier retention approach to manage sensitive data and provide verifiable integrity for logged events.

Tamper-evident database logging for Drupal 11.3 and Drupal 12.

Every entry that lands in the chain hashes its own payload together with the hash of the entry before it in the same chain, and an operator-held secret signs that hash. Insert, modify or delete a record after the fact and the chain breaks at every entry downstream; verification pinpoints the first broken row, and the alteration is provably detectable.

Why

Drupal's dblog module records every event you tell it to, but the rows are plain database writes. Anyone with database write access (a sysadmin, a compromised app account, an attacker who escalated through some other vulnerability) can edit a row, drop a row, or insert a fake row without a trace. For most sites that is acceptable. For audit-worthy applications such as anything subject to regulated retention (notarial acts, financial transactions, medical records), or any system that needs a defensible answer to "who did what, when, with what content", it is not.

audit_trail adds a cryptographic chain on top of selected log entries. It does not stop tampering (no logging mechanism can do that without external storage) but it makes tampering provably detectable, which is the property regulators and auditors care about.

What it does

  • Plugs into Drupal's standard logger pipeline (PSR-3 plus the logger service tag), so any module that calls \Drupal::logger($channel)->info(...) can land in the chain without code changes.
  • Chains entries selectively, on either a per-call 'chain' => TRUE flag in the PSR-3 context or mode: auto chains that capture every entry on their claimed channels automatically. Everything else keeps going to dblog.
  • Stores each chained entry in a dedicated audit_trail table with a publicly-verifiable SHA-256 hash chain plus an operator HMAC layer, and an indexed correlation_id that reads back every row belonging to one logical operation.
  • Groups entries by chain id (defaults to channel; can map multiple channels into one chain via an audit_trail_chain config entity) so verification is independent per chain.
  • Lets each chain choose its own plugins: filter plugins drop events before they become rows, context contributor plugins decide what each row records.
  • Exposes an AuditTrailVerifier service to walk a chain in id order and report every contiguous broken range in a single pass. Signed checkpoints make repeat verification incremental rather than a cold walk from genesis.
  • Rotates the signing secret without breaking history: secrets are config entities backed by the Key module, every row records the secret that signed it, and one chain spans any number of rotations with old rows still verifying.
  • Records a signed operator acknowledgment over a range that is known to be unverifiable, a secret lost in an incident for example, instead of leaving a permanently red verdict.
  • Ships admin pages for entries (filters plus a side-by-side before/after diff), chains, secrets, segments and acknowledgments, and thirteen drush commands covering verification, rotation, the retention lifecycle, archives and timestamping.
  • Submodules add tamper-evident logging for entity CRUD, file operations, user-authentication events, paragraph entities, and RFC-3161 timestamping for external trust anchoring. A sibling Audit Trail for WebDAV module bridges the WebDAV contrib module's events into the chain.

Two-tier retention and lifecycle

Each row carries context in two separately-retained tiers. Permanent context (operator-attested, PII-free metadata: action verbs, resource ids, structural flags) is signed raw and kept for the chain's full retention. Transient context (operational payload: before/after diffs, IP addresses, request URIs) is hash-signed so the bytes themselves can be NULLed at short retention without breaking chain verification: the GDPR-respectful "purge-the-bytes, keep-the-hash" pattern.

A cron-driven lifecycle then moves rows through five stages, working on segments: contiguous id ranges whose bookkeeping row is itself chained, so every transition is attested. Transient-purge NULLs the expired transient bytes, and runs ahead of archive on the same tick so the archive file never seals expired bytes into long retention. Archive exports the range to an NDJSON file under a three-layered HMAC plus a file SHA-256. Live-purge deletes the live rows, the archive file remaining for queryability and restore. File-purge unlinks the NDJSON, segment bookkeeping and anchor hashes remaining so the verifier still bridges across the now-empty range. Compaction folds contiguous file-purged segments into a single bridging row. Retention windows are global with per-chain overrides, and any stage can be turned off by leaving its window empty.

Proof that survives deletion

Old entries get deleted. That is the point of retention, and it used to mean the proof went with them.

Now each batch of entries that leaves the trail is summarized into a short fingerprint, and those fingerprints are linked to each other in order. The link is kept even after the entries are gone. So you can take an old archive file, work out its fingerprint again, and check it against the chain. If the file has been altered, or swapped for another one, or moved to a different place in the order, the check fails.

This check needs no secret. Anyone you hand the archive to can run it themselves, which means an auditor does not have to be trusted with your key, and does not have to take your word for it.

What it does not do

  • It is tamper-evident, not tamper-proof. Anyone with the HMAC secret plus database write access can forge a fresh chain from scratch, but they cannot rewrite the existing chain retroactively without breaking it, or reproduce the RFC-3161 timestamps already anchored to the old head.
  • It does not move the archives off the machine for you. Archiving writes the NDJSON file and records its SHA-256; putting that file on WORM storage (S3 Object Lock, an institutional archival service) is an operator step, and it is what turns tamper-evidence into tamper-resistance.
  • It is not at-rest encryption. The chain provides integrity, not confidentiality; layer DB-side encryption if sensitive data lands in audit rows.
  • It is not a completeness guarantee. The chain protects what reaches it; if a call site bypasses the orchestrator the event never enters the chain.

Requirements

  • Drupal 11.3 or later, or Drupal 12. PHP 8.3 or later.
  • The Key module, a hard runtime dependency. The HMAC secret is a Key entity, so the byte material lives in the provider you choose (file, environment, cloud secret manager, HSM) and never in a config export or a database dump.
  • A configured private file system, if you archive. Archives carry whole audit rows and the module refuses to write them anywhere the web server can serve.
  • The openssl binary on the host, for the audit_trail_tsa submodule only. The status report says so if it is missing.

Status

Under active development on the 1.x branch. Architecture, threat model, configuration, verification and command docs are published at project.pages.drupalcode.org/audit_trail.

Note

The current code base is a complete rewrite with no upgrade path from the prior 7.x module. The original module (created by kevin hankens in 2012) tracked Drupal 7 form submissions and form-element changes via regexp pattern matching, with hooks such as hook_audit_trail_form_change_log_alter. The current version is a Drupal 11 tamper-evidence primitive built on PSR-3 logging with an HMAC chain. Different design, different problem space, different audience.

Depends on

Dependencies of the latest stable release

No dependencies recorded for this project.

Required by

Tracked projects that depend on this one

No tracked projects depend on this one yet.

Activity

Tracked releases
16
Tracked since
May 2026
Latest release
1 week ago
Releases (12 mo)
16 ▲ from 0
Maintenance
Active

Release Timeline

Releases

Version Type Core Release date
1.0.0-alpha14 Pre-release 11 Sep 30, 2026
1.0.0-alpha13 Pre-release 11 Sep 30, 2026
1.0.0-alpha12 Pre-release 11 Sep 23, 2026
1.0.0-alpha11 Pre-release 11 Sep 22, 2026
1.0.0-alpha10 Pre-release 11 Sep 20, 2026
6.x-1.x-dev Dev Sep 20, 2026
1.0.0-alpha9 Pre-release 11 Sep 3, 2026
1.0.0-alpha8 Pre-release 11 Sep 1, 2026
1.0.0-alpha7 Pre-release 11 Sep 1, 2026
1.0.0-alpha6 Pre-release 11 Aug 1, 2026
1.0.0-alpha5 Pre-release 11 Jul 2, 2026
1.0.0-alpha4 Pre-release 11 May 27, 2026
1.0.0-alpha3 Pre-release 11 May 26, 2026
1.0.0-alpha2 Pre-release 11 May 24, 2026
1.0.0-alpha1 Pre-release 11 May 23, 2026
1.x-dev Dev 11 May 23, 2026