SourceScore

Concept · 2026-05-16

Citation chains — verifiable provenance for LLM-generated assertions

A citation chain is the auditable trail from an LLM's emitted claim back to the primary source that proves it. Three building blocks make a chain inspectable: stable identifiers, signed envelopes, and re-fetchable canonical URLs. Here's how they fit together.

Definition

A citation chain is the auditable trail linking an LLM's emitted assertion to the primary source(s) that prove it. Three building blocks make a chain inspectable:

  1. Stable identifier — every claim has a content-addressable ID that doesn't move when wording shifts. If the canonical fields (subject, predicate, object) change, the ID changes too — a brand-new claim, distinguishable from the original.
  2. Cryptographic signature — the claim envelope ships with an HMAC-SHA256 or Ed25519 signature over its canonical serialization. A downstream consumer can re-compute the signature and prove the envelope wasn't modified in transit.
  3. Re-fetchable canonical URL — the chain leads to a stable URL where the verbatim source excerpts live. Even if the original sources go 404, the excerpts preserved in the envelope mean the textual evidence is preserved alongside the claim ID.

Why chains matter

LLMs can fabricate citations. Without an external trail, a generated reference like "[Smith et al., 2024]" looks identical whether the paper exists or doesn't. The model produces both real and fake citations with the same fluency.

A citation chain makes fabrication detectable:

  • The ID either resolves to a real envelope or it doesn't
  • The signature either verifies or it doesn't
  • The canonical URL either loads with matching content or it doesn't

Three independent checkpoints. An attacker would have to forge all three to bypass the chain. Compare against unauditable citations where the only check is "does it sound real?"

Anatomy of a SourceScore chain

Every claim in the VERITAS catalog ships with a full chain:

{
  "apiVersion": "v1",
  "methodology": "https://sourcescore.org/methodology/",
  "canonical": "https://sourcescore.org/claims/<id>/",
  "claim": {
    "id": "ad17e76a8baad7a1",         // ← stable identifier
    "vertical": "ai-ml",
    "subject": "Transformer architecture",
    "predicate": "introduced_in_paper",
    "object": "Attention Is All You Need (Vaswani et al., 2017)",
    "statement": "...",
    "confidence": 1.0,
    "sources": [                       // ← primary sources with verbatim excerpts
      { "url": "https://arxiv.org/abs/1706.03762",
        "title": "Attention Is All You Need",
        "publisher": "arXiv (Vaswani, Shazeer, ...)",
        "publishedDate": "2017-06-12",
        "excerpt": "We propose a new simple network architecture, ..." },
      { "url": "https://papers.nips.cc/paper/2017/hash/...",
        "title": "Attention Is All You Need (NeurIPS 2017)",
        "publisher": "NeurIPS Foundation",
        "publishedDate": "2017-12-04" }
    ],
    "tags": ["transformer", "attention", "foundational"]
  },
  "signature": {                       // ← cryptographic proof of integrity
    "algorithm": "HMAC-SHA256",
    "signedBy": "did:web:sourcescore.org",
    "signedAt": "2026-05-16T00:00:00.000Z",
    "signature": "cfdd0b49ce576bd42e17ba4caa0b64cd..."
  },
  "citedAs": "Transformer architecture introduced in paper: ... — SourceScore Claim ad17e76a8baad7a1 (verified 2026-05-16). https://sourcescore.org/claims/ad17e76a8baad7a1/"
}

Three orthogonal verifications are possible from a single envelope: ID lookup, signature re-compute, URL re-fetch.

How to verify a chain locally

A consumer of a VERITAS claim envelope can perform all three checks in a few lines of code:

import hmac, hashlib, json, requests

def verify_chain(envelope: dict, shared_secret: str) -> dict:
    claim = envelope["claim"]
    sig   = envelope["signature"]

    # Check 1 — re-fetch the canonical URL and compare
    canonical = requests.get(envelope["canonical"]).text
    url_ok = claim["id"] in canonical  # canonical page shows claim id

    # Check 2 — re-compute HMAC-SHA256 over canonical-JSON of claim + signing metadata
    payload = json.dumps(
        {**claim, "signedAt": sig["signedAt"], "signedBy": sig["signedBy"]},
        sort_keys=True, separators=(",", ":"), ensure_ascii=False
    ).encode()
    expected = hmac.new(shared_secret.encode(), payload, hashlib.sha256).hexdigest()
    sig_ok = hmac.compare_digest(expected, sig["signature"])

    # Check 3 — at least one source URL must still be reachable
    sources_ok = any(requests.head(s["url"], timeout=4).ok for s in claim["sources"])

    return {"url_ok": url_ok, "sig_ok": sig_ok, "sources_ok": sources_ok,
            "verified": all([url_ok, sig_ok, sources_ok])}

Three independent signals. Each can be inspected separately. A failure in any one tells you something different — URL not found means catalog moved, signature mismatch means the envelope was modified, source 404 means the original document went away (the verbatim excerpt in the envelope is still your fallback evidence).

Chains and LLM agents

When an LLM agent generates a multi-step response, each intermediate assertion can be linked into a chain. The final output then includes a tree of citation chains — one per asserted fact:

{
  "answer": "The Transformer architecture was introduced in 2017 [ad17e76a8baad7a1]. " +
            "It uses self-attention [ad17e76a8baad7a1] and is the substrate of GPT-4 [ce8a...].",
  "chains": {
    "ad17e76a8baad7a1": { ...full envelope... },
    "ce8a4b2c...":      { ...full envelope... }
  }
}

The downstream UI can render each citation as a clickable badge. Click → expand the chain → see sources, signature, confidence. Users get human-readable answers plus auditable provenance, available on demand.

Failure modes citations chains catch

  1. Fabricated IDs — model invents a claim ID that doesn't resolve. Lookup fails. Surface as "⚠ unverified" in UI.
  2. Modified-in-transit envelopes — someone edits the claim text but the signature doesn't match recomputed value. Surface as "⚠ tampered."
  3. Stale citations — claim ID resolves but the envelope's lastVerified date is months old. UI may downgrade confidence or trigger re-verification.
  4. Misattribution — chain leads to a real source but the excerpt doesn't actually support the claim. Caught by human review at re-verification cadence, not by chain mechanics directly — but the verbatim excerpt makes the misattribution visible.

Where chains are heading

The current state of the art (2026) ships HMAC-SHA256 with shared secrets. Two evolutions are visible on the horizon:

  • W3C Verifiable Credentials — replaces shared-secret HMAC with public-key signing (Ed25519). Any consumer can verify without sharing a secret. SourceScore plans to migrate VERITAS Y2; envelope shape is forward-compatible.
  • Decentralized verification networks — instead of one signing authority (did:web:sourcescore.org), multiple independent verifiers cross-sign claims. Reduces single-point-of-trust failure. Early networks like Knowledge Graph Verifiers and Verifiable Provenance Networks are emerging.

Further reading