Install

Works with Drupal: ^11.3

Using Composer to manage Drupal site dependencies

Alternative installation files

Download tar.gz 351.19 KB
MD5: f9d9ec3eb81a104bea666fc6de088591
SHA-1: e23022d76a844176f6884ddee05fc258cced40e2
SHA-256: 12a207ed723b894c49b77a208f9b47dc9e4df89abf838c1835afa9f96f0c270d
Download zip 481.37 KB
MD5: 111ecfacc0237b80ca8abbe9222e116b
SHA-1: eeab7c151cc4b5082554db081aa373e00450266f
SHA-256: f5c1d4d86df260175a637e7d0022adc53c543bd8f6a28995fd5e7e06ce0ae05a

Release notes

The fourth alpha of Content Credentials. A site on the pure-PHP route can now keep, for every file it reads, the evidence its verdict rested on: the certificates, time-stamps and trust lists, with a hash of the bytes read. The records are chained, so a change shows, and editors see them beside the suggestion. The archive is off by default. Run drush updatedb after updating. No dependency changes. It is still an alpha: it has never run in production, and this project is not covered by Drupal's security advisory policy.

What changed since 1.0.0-alpha3

  • Evidence archive, on the verifier route, off by default (#3634256). Turn it on under Evidence archive in the settings. Every verifier read that finds a credential, trusted or not, keeps the verifier's evidence document with the file, the content it was read for, the SHA-256 of the bytes read and the verdict. Deleting the file, or the content, erases the document and keeps the row.
  • Readable beside the suggestion (#3634263). The edit form shows a block of this module's own after AI Disclosure's widget, which is not changed. Its link opens a view in a dialog: who signed, why it is trusted or not and which time counted, then the technical details and the JSON document.
  • Chained, with its trust lists (#3634272). Each record carries the hash of the one before it; the status report walks the chain and each new head is logged. The trust lists a verdict was judged against are stored once and can be downloaded.
  • Who may see it (#3634372, #3634481). The new restricted permission View content credentials evidence, plus view access to the content the file was read for.
  • The verifier route reads with the two trust lists rather than a settings document. No verdict changes; the certificate limit is now 256 per field instead of 256 for both together.

Install or update

composer require drupal/ai_disclosure:^1.0.0-alpha3
composer require drupal/content_credentials:^1.0@alpha

# For the pure-PHP route:
composer require provemark/c2pa-verifier:^0.10

# From an earlier alpha:
composer update drupal/content_credentials
drush updatedb
drush cache:rebuild

Composer is required. AI Disclosure 1.0.0-beta1 or later is recommended.

Requirements

  • Drupal 11.3 or later; PHP 8.3 or later.
  • AI Disclosure 1.0.0-alpha3 or later.
  • provemark/content-credentials 0.20.
  • For the pure-PHP route, provemark/c2pa-verifier 0.10.

Known issues

New in alpha4, about the evidence archive:

  • No retention setting, no list page and no way to delete a record: while the archive is on, the table grows by one row per read. Only uninstalling the module removes the rows.
  • The chain shows a change; it does not prevent one. Whoever can rewrite the table can recompute it; the copy outside the database is the head logged at info level, and only if your logs leave the server. The status report checks each record's columns and link, not its document, and cannot tell that the newest records were removed. Erasing a document is outside the chain.
  • Evidence only on the verifier route, only what the file staples (no revocation source is asked), and not above 1 MiB.
  • Access is the content's own, on its current revision; field access is not asked. A record whose content was deleted needs Administer content credentials as well. Kept trust lists download with the evidence permission alone. Content that reuses a deleted entity's ID opens the old content's records.
  • Evidence can be personal data: a certificate can name the person who signed.

Unchanged from alpha3:

  • A kept original can be read only by the PHP user, on the host, that handled the upload. A cron run as another user, or on a host that does not share temporary://, reads the scaled file instead: no suggestion, and nothing is logged. Run cron as the web server's user.
  • Sites that share one temporary directory share the kept copies: one site's cron removes another's unclaimed copies after six hours, and uninstalling the module on one site removes them all. Give each site its own temporary directory.
  • An upload that another validator then refuses can leave its copy for six hours. It is never read.
  • drush queue:run content_credentials_read ends with an error on every run while the reading service is down; cron waits quietly. The queued files are kept either way.
  • The pure-PHP verifier route is stricter than c2pa-rs on files signed elsewhere: in the library's measurement 47 of 482 files that c2pa-rs calls valid did not read valid through it, and on that route those uploads get no suggestion.
  • The ext-c2pa route skips MP3 files, because ext-c2pa v0.1.0 can end the PHP process on a malformed one: by name, and any file that begins with an ID3 tag whatever it is called (#3630240). The other routes read them. Where people you do not trust can upload files, prefer the service or verifier route.
  • The ext-c2pa route needs about 6.5 MiB of PHP memory per MB of manifest (not of file: a 13 MB photo with a normal manifest is fine). A crafted manifest of over about 10 MB per 128 MB of memory exhausts it, and the item then fails on every cron run until it is deleted. Raise cron's memory_limit, or use the verifier route, which refuses such manifests.
  • Trust anchors set outside the settings form (drush, a configuration import, settings.php) are not checked; the form checks them for both in-process routes. After changing them another way, upload one signed file and look at the log.
  • The ext-c2pa route accepts a PEM block that is not a certificate: valid base64 that does not decode to one is refused neither by the extension nor by the form, and vouches for nothing: with only such a block in the field, every upload reads as untrusted while the status report says the route works. The verifier route refuses it. If uploads you expect to be trusted log Untrusted manifest, check the anchors.
  • One suggestion per entity: with several credentialed files on one entity the last one read decides. With AI Disclosure 1.0.0-alpha3 a later trusted upload sets an editor's accepted or dismissed decision back to pending; from 1.0.0-beta1 (#102, #106, #107, #108) the decision is kept when the new file reads the same, with the same grade and the same note, which names the source type, signer and software agents. A file that reads differently goes back to pending; when its grade equals the one already set, the form says so and offers only Dismiss. A file that reads lower than the grade in force gets no suggestion, and an older pending one from this module is removed. That holds even when the stricter file stays on the entity: someone who can add a trusted file that reads lower can make a pending stricter suggestion disappear. The disclosure already set is never lowered, but check the files on an entity rather than relying on a pending suggestion alone.
  • Removing a credentialed file, or replacing it with one without credentials, leaves its suggestion pending; dismiss it on the entity form.
  • The grade map can only reorder the grades AI Disclosure ties to a term: the form offers every grade, a row naming another grade does nothing (the log says so), and if the preferred grade is deleted the next one listed wins, which for trained-model images is AI deep fake.
  • Sites that use Media opt in the media type: an image attached through Media gets its suggestion on the media item, which is where AI Disclosure keeps an image's disclosure. Each media file is read twice, once through its thumbnail.
  • Translations are not handled: the suggestion is stored under the default language.
  • The service route trusts the service's answer, and the form accepts an http:// address. Use https:// unless the service runs on the same host; the status report does not warn about it yet.
  • The test-root warning recognises the test root only: the status report does not warn while a certificate issued under it is among the anchors, such as the es256 certificate in c2patool's sample folder, whose key is public too. See the README on files that another module re-signs.
  • A site that re-signs uploads, such as one running C2PA Sign, needs its own certificate among the trust anchors here; otherwise every upload it signs is logged as untrusted and gets no suggestion (#3629737).
  • C2PA Sign releases before 1.5.0 lose the origin of a file in the current C2PA 2.x format on the way in; no reader can recover it. Use C2PA Sign 1.5.0 or later with a current c2patool (#3632098).
  • AI Disclosure 1.0.0-alpha3's @EntityType annotations show as two deprecations on Drupal 11.4; 1.0.0-beta1 clears them.
  • The service and ext-c2pa routes read with c2pa-rs, which still calls a file trusted when its hash leaves the picture or the media outside what is signed, with the pixels changed after signing (measured by the verifier's maintainers with c2patool 0.28.1 and 0.28.2). The verifier route refuses those files. This module cannot change what c2pa-rs reports.
  • Never run in production.

The full list of changes and known issues is in the CHANGELOG.

Created by: maurice1969
Created on: 2 Nov 2026 at 05:45 UTC
Last updated: 2 Nov 2026 at 05:45 UTC
New features

Other releases