Drupal is a registered trademark of Dries Buytaert
File Entity (fieldable files) 8.x-2.7 Minor update available for module file_entity (8.x-2.7). Field Group 4.1.0-alpha4 New alpha version released for module field_group (4.1.0-alpha4). CKEditor 5 Plugin Pack 1.5.4 Minor update available for module ckeditor5_plugin_pack (1.5.4). CKEditor 5 Premium Features 1.8.3 Minor update available for module ckeditor5_premium_features (1.8.3). Drupal Canvas 1.9.0 Minor update available for module canvas (1.9.0). CKEditor 4 LTS - WYSIWYG HTML editor 1.0.5 Minor update available for module ckeditor_lts (1.0.5). Token Content Access 3.1.2 Minor update available for module tca (3.1.2). Islandora Mirador 3.0.0 Major update available for module islandora_mirador (3.0.0). Configuration development 8.x-1.12 Module config_devel updated after 8 months of inactivity (8.x-1.12). Provus Mega Menu Module provus_mega_menu crossed 1,000 active installs.

Tamper-evident audit logging for Drupal, usable by any module.

Each entry's hash covers its own content and the previous entry's hash. Any later insertion, deletion or edit breaks that chain and is detectable by an independent verification pass. With an HMAC key configured, forging a repair also requires the key, so an edit made straight in the database cannot be quietly papered over.

The difference that matters: not "the application says it logged that", but a record that can be shown not to have been altered since it was written.

Using it

Inject Drupal\audit_chain\AuditChainLoggerInterface and write an entry:

\Drupal::service('audit_chain.logger')->log('personnel', 'field_read', ['entity_type' => 'node', 'id' => $node->id(), 'field' => 'field_salary']);

entity_type, bundle, id and label become indexed columns; every other key is serialised into the metadata column. All of it — plus the actor, timestamp, IP and user agent — is covered by the hash.

The first argument is the channel, a short name identifying the consumer. It is bound into the hash, so an entry cannot be re-attributed to a different channel after the fact — which matters when one channel is the thing being audited.

Verifying

drush audit-chain:verify

The exit code is the contract: non-zero means the chain does not verify. Wire it into monitoring or a deploy gate without parsing output.

Two constraints for consumers

Do not log per access check. A hook like hook_entity_field_access() fires per field, per entity, per render. An entry each time produces a chain nobody can read and a write-amplified request. Dedupe per request and flush once at kernel.terminate.

Rotating the encryption profile orphans existing entries. Metadata encrypted under one profile cannot be decrypted after switching to another, and the chain is computed over the plaintext — so those entries stop verifying, and the failure looks exactly like tampering. Export or re-encrypt first.

Configuration

Configuration → System → Audit Chain:

  • Signing key — a Key entity. Empty means plain SHA-256, which detects accidental corruption and careless edits but not someone with database access recomputing the chain. Store the key outside the database.
  • Encryption profile — encrypts metadata at rest. See the rotation caveat above.
  • Stream entries — emits each entry to the audit_chain logger channel as a structured record, so syslog or Monolog can forward it to a SIEM without polling.

What it does not do

  • It does not make deletion impossible. Nothing at the application layer can. It makes deletion evident: the seam shows at the next verification.
  • It does not order events across servers. The chain is one sequence in one database.
  • It does not replace dblog or syslog. Those are operational logs. This is an evidentiary one, and deliberately narrower.

Origin

Extracted from MCP Sentinel, where it had grown up as the audit trail for AI-agent traffic. It was never specific to that: personnel-record reads, permission grants, configuration changes and break-glass logins all want the same guarantee, and none of them should require an AI-governance module to get it. MCP Sentinel remains its first consumer.

Requirements

Drupal 10.6+ or 11.3+, Key, and Encrypt.

Activity

Total releases
2
First release
Jul 2026
Latest release
35 minutes ago
Releases (12 mo)
2 ▲ from 0
Maintenance
Active

Releases

Version Type Release date
1.0.0 Stable Jul 29, 2026
1.x-dev Dev Jul 29, 2026