VARSEL ·
Conshultocracy AB · Red Flag Screening Service

AI-Transparency Marking: Trust Anchor, Specification and Verification

ATV-VARSEL-001 · v1.0 · 2026-10-26 · External — public

Varsel — AI-Transparency Marking: Trust Anchor, Specification and Verification

How to check that a Varsel document carries its machine-readable AI-content marking

Field Value
Document ID ATV-VARSEL-001
Version 1.0
Date 2026-10-26
Classification External — public; may be shared with anyone who holds a Varsel document
Owner CEO, Conshultocracy AB
Review cycle On any change to the signing certificate, the manifest specification or the carriers; otherwise annual

Why this document exists. Since release v315 (2026-10-18) the PDFs that Varsel returns from its screening and enrichment document routes carry a signed, machine-readable statement that the document contains AI-generated content, and since v316 (2026-10-18) the same statement travels in the report HTML and in the JSON preview response. The statement is signed with a certificate that we issued ourselves. A signature is only worth something if the public can check it against a published anchor, so this document publishes that anchor, the exact format of the statement, and two ways to verify it: a small reference script and a manual recipe with standard tools. It is written so a compliance team or an authority can run the checks without asking us anything.

It is written to be checkable. Every constant below is read from the deployed code, and a test in our code base fails if this document and the code drift apart.


Contents

  1. What the marking is, and what it is not
  2. The trust anchor
  3. The manifest (specification varsel-ai-transparency/1.0)
  4. The three carriers
  5. How to verify
  6. What a result means, and what it does not
  7. Reporting a discrepancy

1. What the marking is, and what it is not

It is a machine-readable statement, embedded in the document, that parts of the document were produced by AI systems, naming the AI providers and models our system recorded during that run and the time the document was generated. It is the measure we apply under Article 50(2) of the EU AI Act (Regulation (EU) 2024/1689) as the provider of the Varsel AI system. A visible label on the cover of the PDF says the same thing in words, with the EU "AI" icon (alternative text for assistive technology: "EU AI label icon: this document contains AI-generated content"). The label and the marking are both applied on the screening and enrichment document routes and both are fail-open: a fault produces a document without them rather than no document (section 6).

It is not a statement about the accuracy of the screening, a statement that the content was reviewed, or a determination of anything about the screened entity. The signature binds the marking to the file; it vouches for nothing else. Varsel surfaces sourced signals; the decision on what they mean, and the accountability for that decision, stay with the reader of the report.

The certificate is self-signed. We issued it ourselves; it is not chained to a public certificate authority or a trust list. Consequences, stated plainly:

2. The trust anchor

Production certificate (signs the documents returned by the production service since 2026-10-18, release v315):

Field Value
Subject CN=Varsel AI transparency, O=Conshultocracy AB, C=SE
Issuer the same (self-signed)
Serial number 0x4b7198f4b5735a75f169def229249abbf4c5e4d0
Valid 2026-10-17 11:13:15 UTC to 2036-10-15 11:13:15 UTC
Key ECDSA, curve P-256 (secp256r1); signature algorithm ecdsa-with-SHA256
SHA-256 fingerprint of the DER-encoded certificate 64082b8c14bc6ffc457d149d14b67a73256bd98b7ab717121c842fe60be91abf
File varsel-ai-transparency-prod-2026-10-18.pem (SHA-256 of the PEM file as published: 9103f4ab9c8e195b50b31d7b4da159cd733f188460de3e0608f7419b9a21ebb2)
Published at https://www.conshultocracy.com/tools/varsel/ai-transparency (the canonical copy, live since 2026-10-26) and in this document
-----BEGIN CERTIFICATE-----
MIIBtjCCAVygAwIBAgIUS3GY9LVzWnXxad7yKSSau/TF5NAwCgYIKoZIzj0EAwIw
SjEfMB0GA1UEAwwWVmFyc2VsIEFJIHRyYW5zcGFyZW5jeTEaMBgGA1UECgwRQ29u
c2h1bHRvY3JhY3kgQUIxCzAJBgNVBAYTAlNFMB4XDTI2MTAxNzExMTMxNVoXDTM2
MTAxNTExMTMxNVowSjEfMB0GA1UEAwwWVmFyc2VsIEFJIHRyYW5zcGFyZW5jeTEa
MBgGA1UECgwRQ29uc2h1bHRvY3JhY3kgQUIxCzAJBgNVBAYTAlNFMFkwEwYHKoZI
zj0CAQYIKoZIzj0DAQcDQgAE+S8i769dCmKBZc+0QX+GmoYmgf3a7ywSfdpekp9y
pEo0gzKOYZFoXxs9UdZndj+g0PFa21QtlT2+yZZP5agu96MgMB4wDAYDVR0TAQH/
BAIwADAOBgNVHQ8BAf8EBAMCBsAwCgYIKoZIzj0EAwIDSAAwRQIhALN+Z0OZHcGA
7Yo9arg1F9KQQFbs+BCEFduHtJITdnbZAiBzLOgsgkFRG6UoUHOGG4Z9EHvbMJc+
27rLF5YA7XdClw==
-----END CERTIFICATE-----

Key custody. The private key exists in exactly one place: as a secret of the production application on our hosting platform. It is not in source control, not in any file, not on any laptop, and it is never logged. The signer is rebuilt from that secret at call time and the key material never leaves the process. Our staging environment signs with a different key pair; its certificate is not published because no customer document is ever signed with it.

Rotation. If the key is replaced (compromise, expiry, or a deliberate rotation), the new certificate is added to the table above with its first-use date, and the old one stays listed so that documents signed earlier remain verifiable. A document is verified against the certificate that was in use on its generated_at date. We will announce a rotation in the Trust and Compliance Pack's revision history.

Documents generated before 2026-10-18 (production release v314 and earlier) carry no marking. The verifier reports them as unmarked (exit code 3); that is correct, not a failure.

3. The manifest (specification varsel-ai-transparency/1.0)

The manifest is one JSON object. All three carriers carry the same object for the same document, built once per document from the same run data and the same clock reading.

Field Type Value or meaning
spec string varsel-ai-transparency/1.0
statement string This document contains AI-generated content. Parts of it were generated by AI systems; models lists the providers recorded during this run.
system string Varsel - Red Flag Screener
provider string Conshultocracy AB (559419-4697) (the provider of the AI system, Art. 3(3))
generated_at string UTC, YYYY-MM-DDTHH:MM:SSZ, no sub-seconds. One clock reading per document: it is also the signing time of the PDF signature, the time printed on the PDF cover and the date in the PDF file name
ai_generated string partial (the document mixes AI-produced text with deterministic text and sourced data)
digital_source_type string http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia (the IPTC vocabulary term for AI-generated content)
models array One entry per AI role that the run recorded, see below. May be empty for a document whose run recorded no AI call
models_scope string Providers recorded during this run. AI uses without a per-run provider record are not listed.

Each entry of models has exactly these fields:

Field Values (closed lists)
role one of baseline_risk_analysis, market_reputation_analysis, person_background_web_search, adverse_media_web_search, high_risk_country_web_search, enrichment_concern_decomposition, enrichment_narrative_synthesis, enrichment_web_research
provider one of google, openai, perplexity, unknown
model the model identifier recorded when the answer arrived (lower-case, at most 64 characters), or unknown
path primary, fallback or unknown (whether the primary provider for that role answered or the fallback did)
count present only when the same provider, model and path answered more than once for that role (for example several persons in a person-background search)

What the manifest says, and what it deliberately does not contain. It lists what the run recorded. AI uses in the product that have no per-run provider record yet are not listed, and models_scope says so rather than implying completeness (closing that gap is tracked work; see the Trust and Compliance Pack, section 10). The manifest never contains the screened entity's name, any person's name, a jurisdiction, a user or report identifier, a content hash of the report or any finding. It is safe to forward with the document.

Canonical form. The signed and hashed representation is the JSON serialisation with keys sorted at every level, no whitespace, and non-ASCII characters left as UTF-8 (in Python terms: json.dumps(manifest, sort_keys=True, separators=(",", ":"), ensure_ascii=False)). Its SHA-256, computed over the UTF-8 bytes, is carried next to it in every carrier as manifest_sha256 so a verifier can detect a manifest that was edited after hashing.

4. The three carriers

4.1 PDF (the screening report, its dossier variant and the enrichment PDF; applied fail-open)

Element Specification
XMP metadata packet Exactly one x:xmpmeta packet in the file. In its rdf:Description, namespace https://varsel.nu/ns/ai-transparency/1.0/ (prefix varsel): property varsel:aiManifest = the canonical manifest text; varsel:aiManifestSha256 = its SHA-256 (hex). In namespace http://iptc.org/std/Iptc4xmpExt/2008-02-29/ (prefix Iptc4xmpExt): Iptc4xmpExt:DigitalSourceType with an rdf:resource attribute equal to the digital_source_type value
Digital signature One PAdES signature (CMS, detached, PDF signature dictionary) in a signature field named VarselAITransparency. It covers the entire file as returned, including the XMP packet: any later change to the file (even a metadata edit) invalidates it. Reason string: Machine-readable AI-content marking by Varsel (Conshultocracy AB). The signing time in the signature (/M) equals the manifest's generated_at
Order of production render, write XMP, sign, then the audit footer fingerprint reads the final bytes. The signature is the last modification; no timestamp authority is involved
Visible label On the cover (screening and enrichment routes; rendered fail-open): the EU "AI" icon with the alternative text EU AI label icon: this document contains AI-generated content, AI-generated content: parts of this document were produced by AI systems (EU AI Act Art. 50). and, only when the signing key was configured for that run, A machine-readable AI-transparency manifest is embedded in this file., plus the generation time in UTC

4.2 HTML (the report HTML, from which the PDF is rendered)

Four <meta> elements in the document head, each exactly once:

name content
varsel-ai-transparency the canonical manifest text
varsel-ai-transparency-sha256 its SHA-256 (hex)
varsel-ai-transparency-signature base64 of the DER-encoded signature over the UTF-8 bytes of the canonical manifest (present only when signed)
varsel-ai-transparency-cert-sha256 SHA-256 (hex) of the DER-encoded signing certificate (present only when signed)

The signature algorithm follows the certificate's key: ecdsa-p256-sha256 for the production certificate above (ECDSA over SHA-256, DER-encoded signature).

4.3 JSON (POST /screen/preview response)

One additive top-level key, ai_transparency, an object with exactly these fields:

Field Meaning
manifest the manifest object (section 3), or null when it could not be built
manifest_sha256 SHA-256 (hex) of the canonical form, or null
signed true when a signature is present
reason ok when signed; otherwise a short code, for example no_signing_key
signature null, or an object with algorithm (for example ecdsa-p256-sha256), value (base64 DER signature), certificate_sha256 (hex SHA-256 of the DER certificate, to match against the anchor) and signed_over = manifest_canonical_json_utf8

The certificate itself is not embedded in any carrier. A verifier obtains it from this document or from the published page and compares fingerprints; a self-asserted certificate inside the file would prove nothing.

5. How to verify

The script verify_varsel_ai_transparency.py is published next to the certificate on https://www.conshultocracy.com/tools/varsel/ai-transparency. It contains no Varsel code and makes no network connection; it reads the file you give it and prints every check it performs.

pip install cryptography pikepdf pyHanko
python verify_varsel_ai_transparency.py Varsel-Example-AB-2026-10-26.pdf varsel-ai-transparency-prod-2026-10-18.pem

Expected on a marked PDF: a first line with the file's SHA-256, a list of [ok] checks, the lines without anchor: intact=True valid=True trusted=False and with anchor: intact=True valid=True trusted=True coverage=SignatureCoverageLevel.ENTIRE_FILE modification=ModificationLevel.NONE, the manifest in full, and RESULT: MARKED OK (verified against anchor ...). Always pass the anchor. Without it the script can only check that the file is internally consistent; it then reports RESULT: MARKED, NOT VERIFIED and exits 4, never MARKED OK, because a forged file signed with anyone's key would pass the internal checks.

The same script reads a report HTML file (python verify_varsel_ai_transparency.py report.html anchor.pem) and a saved preview response (python verify_varsel_ai_transparency.py --json preview.json anchor.pem).

Exit codes: 0 marked, every check passed and the signature verified against the anchor; 4 marked and internally consistent but no anchor given (unverified); 3 unmarked (no carrier, or a carrier without a signature, in all three modes); 1 marked but at least one check failed (the failed checks are named); 2 usage or environment error (bad arguments, an anchor file that is not a PEM certificate, a missing library, or an internal error while reading the file). The script never ends in a Python traceback: a reading error is reported as exit 2.

Checks the script performs on a PDF, in order: exactly one XMP packet; the manifest read by two independent readers (pikepdf and a plain XML scan of the file bytes) agrees; the manifest's key set, canonical form, stored hash, spec, digital_source_type and generated_at format; the DigitalSourceType attribute; exactly one signature in the field VarselAITransparency; the signature is intact and valid without any anchor; with the anchor it is trusted, covers the entire file and shows no modification; the signing time equals generated_at.

5.2 By hand, with standard tools

  1. Check the anchor you hold. Compare the fingerprint with the one in section 2 and with the copy on our website:
    openssl x509 -in varsel-ai-transparency-prod-2026-10-18.pem -noout -fingerprint -sha256
  2. Validate the PDF signature with pyHanko's command line (pip install pyhanko-cli), using our certificate as the only trust root:
    pyhanko sign validate --trust varsel-ai-transparency-prod-2026-10-18.pem --trust-replace --no-revocation-check Varsel-Example-AB-2026-10-26.pdf
    Expected output line (checked by us on a production document, pyHanko CLI 0.6.0): VarselAITransparency:64082b8c14bc6ffc457d149d14b67a73256bd98b7ab717121c842fe60be91abf:INTACT:TRUSTED,UNTOUCHED. Without --trust the same command reports INTACT:UNTRUSTED,UNTOUCHED and exits with "Validation failed", which is the self-signed reading described in section 1, not an altered document.
  3. Read the manifest from the XMP packet:
    python -c "import pikepdf,sys; m=pikepdf.open(sys.argv[1]).open_metadata(); print(m['{https://varsel.nu/ns/ai-transparency/1.0/}aiManifest']); print(m['{https://varsel.nu/ns/ai-transparency/1.0/}aiManifestSha256'])" Varsel-Example-AB-2026-10-26.pdf
    Recompute the SHA-256 of the printed manifest text (UTF-8) and compare it with the stored hash. Any text editor or sha256sum will do; the manifest text must be hashed exactly as printed, without a trailing newline.
  4. HTML or JSON carrier: extract the manifest text and the base64 signature, decode the signature, and verify it with the certificate's public key as an ECDSA P-256 signature over SHA-256 of the UTF-8 manifest bytes (openssl dgst -sha256 -verify <pubkey.pem> -signature <sig.der> <manifest.txt> after extracting the public key with openssl x509 -pubkey -noout). The certificate_sha256 value (or the -cert-sha256 meta) must equal the anchor's fingerprint.

5.3 In a PDF viewer

Mainstream viewers show the signature panel for the field VarselAITransparency. Until you import our certificate as a trusted identity in that viewer, expect wording along the lines of "signature is valid, but the signer's identity is unknown or not trusted". That is the self-signed reading; the document has not been altered. The exact wording differs between viewers and versions, and we have not verified it in each one; the command-line checks above are the authoritative route.

6. What a result means, and what it does not

A passing verification establishes that the file you hold is byte-for-byte the file our production service signed at the stated time, that it carries a manifest stating the document contains AI-generated content, and that the manifest lists the AI providers and models the run recorded.

It does not establish that the screening is accurate or complete, that any finding is true, that the document was reviewed by a person, or anything about the screened entity. The reader assesses the signals in the report and decides; Varsel does not decide, and the signature does not change that.

Known limits, stated plainly:

7. Reporting a discrepancy

If a document from our production service dated 2026-10-18 or later verifies as unmarked, fails a check, or carries a manifest that contradicts the report's own AI-methodology section, tell us at privacy@conshultocracy.com with the file's SHA-256 (the verifier's first output line) and the generated_at value. We treat that as a defect, not a support question. Do not send the document itself unless we ask: the hash and the time are enough to find the event in our audit trail, which stores no document content.


This document describes Conshultocracy AB's AI-transparency marking for the Varsel service. It is provided so that holders of a Varsel document can verify the marking themselves. It is not legal advice, and it does not vary the terms of any agreement between us.