Witness-DAO

Docs & audits / Product

Contents

Data protection

This file exists because a data-protection audit found that across ~22,000 lines of source, four markdown rule files, a README and a LIMITATIONS file, the strings "GDPR", "personal data", "data subject", "retention" and "erasure" appeared exactly zero times — in a product whose explicit purpose is attributing governance actions to a named individual.

LIMITATIONS.md opens by saying the product's entire value proposition is not over-claiming. That discipline had been applied rigorously to evidentiary truth and cryptographic honesty, and not at all to data protection. This document extends it. It is written in the same register: what the code actually does, what it does not, and what remains a question rather than an answer.

Not legal advice, and not a compliance claim. Nobody who wrote this is your lawyer, and nothing here asserts that this product or your deployment of it complies with anything. Every conclusion marked (for counsel) is a question, not a determination. What this document does supply is the technical facts a DPO needs in order to ask the right questions, plus the controls the product now ships so those answers can be implemented and evidenced.


Contents

  1. The one-paragraph summary
  2. What is processed
  3. Are wallet addresses personal data here?
  4. Art. 9 special-category risk
  5. Roles: controller, processor, sub-processors
  6. Transfers (Chapter V) and the residency control
  7. Minimisation: the content policy
  8. Retention and erasure
  9. Rectification and supersession
  10. Art. 14 notice: the structural problem
  11. The dossier problem
  12. Metadata leakage
  13. DPIA input pack
  14. Art. 30 record template
  15. Configuration reference
  16. What is still missing

1. The one-paragraph summary

Witness-DAO builds permanent, externally anchored behavioural records about identified natural persons — wallet address, voting choice, voting power, free-text rationale, treasury destination — and its selling point is that the resulting artefact bears on a named human's personal legal liability. That is high-risk processing on several EDPB DPIA criteria at once. The saving architectural fact, verified line by line, is that only digests leave the building: OpenTimestamps, the RFC-3161 TSAs and Sigstore Rekor receive a Merkle root or a hash of one, never a body. Plaintext lives in exactly two erasable places — the VDA SaaS and the local journal — which makes crypto-shredding the correct and available erasure strategy rather than an impossibility. The product now ships that strategy (witness-dao erase), a retention policy and purge (witness-dao purge), a minimisation gate that defaults to sealing digests instead of third-party prose, an enforced residency allowlist, a supersession mechanism, and purpose capture plus access logging on the dossier path. What it does not ship is a lawful basis, a DPIA, a processor contract, a limitation-period analysis or a privacy notice. Those are the deploying enterprise's, and they cannot be supplied by a library.


2. What is processed

The authoritative list is decision.inputs in src/seal/sealer.ts. Seven fields form the canonical body that bodyHash digests, that the Ed25519 signature covers, and that the anchored Merkle root commits to. The code's own comment is "These seven fields ARE the evidence."

Field Content Personal data?
kind event type (vote.cast, multisig.execution, …) no, but it types the behaviour
eventId provider-scoped identifier usually derived from ids above
daoId Snapshot space / Safe address / Governor address no
occurredAt ISO-8601 instant the act occurred yes, in combination — it timestamps a person's act
actors addresses that acted, lower-cased yes — see §3
binding txHash, proposalId, ipfsCid, safeTxHash, signatureDigest yes, in combination
detail provider-specific, unconstrained object yes — see the table below

Additionally, decision.reasoning is a generated sentence that interpolates the full actor list (Actors: 0x…, 0x…), so every record carries the addresses twice. governingRule.ruleText — your own ratified rule text — is sealed verbatim into every matching record.

What each shipped provider puts in `detail`

Under the default content policy (hash-only, see §7). Fields marked ⚠ are sealed verbatim only when you set WITNESS_DAO_CONTENT_FREETEXT=full.

Source Sealed Reference
Snapshot vote.cast voter address (in actors), choice, choiceLabels, votingPower, reasonDigest + reasonLength (⚠ reason under full), proposalId src/binding/snapshot.ts
Snapshot proposal.created author address, titleDigest, bodyDigest + bodyLength (⚠ title, bodyExcerpt under full), choices, public url src/binding/snapshot.ts
Snapshot proposal.tally no actors by design; actorSetRoot + actorSetSize (a Merkle commitment, not the roll), scores, counts, completeness flags src/binding/snapshot.ts
Governor vote.cast voter, support, supportLabel, weight, reasonDigest + reasonLength (⚠ reason under full), params src/binding/governor.ts
Governor proposal.created proposer, targets, values, calldata selector + digest (⚠ preview under full), descriptionDigest + descriptionLength (⚠ descriptionExcerpt under full) src/binding/governor.ts
Safe multisig.confirmation signer owner address, signatureType, confirmationsRequired, confirmationsCollected src/binding/safe.ts
Safe multisig.execution executor, proposer, confirmingOwners (the full sorted signer list), to, value, selector, decodedMethod src/binding/safe.ts
Safe treasury.transfer ERC-20 to (recipient address), from, amount, executionTxHash src/binding/safe.ts

The Safe provider ingests no unbounded free text — every field above is a structured identifier or a number — so the content policy does not apply to it. That is a property of the current provider, not a guarantee about future ones.

Categories of data subject: DAO voters (potentially thousands, most anonymous to you); multisig signers (few, named, and the most intensively processed); proposal authors; treasury transfer recipients. Only the first category is plausibly your customer. See §10.


3. Are wallet addresses personal data here?

The vendor's position: yes, and the product is designed for a purpose that makes them so. Treat that as settled internally and stop relitigating it per deployment.

(For counsel: confirm, and confirm separately whether the Safe confirmingOwners array — a named group's collective decision — attracts any additional treatment.)

The orthodox GDPR answer is that a pseudonymous identifier is personal data where the controller or any other party has reasonable means to link it to a natural person (Recital 26; Breyer C-582/14; and the CJEU's 2025 EDPS v SRB judgment, which turned on the recipient's means of re-identification). DAO culture asserts addresses are pseudonymous and therefore out of scope.

In this product that argument collapses on its own value proposition. The liability-defence pack takes a subject address, is built "for a named individual", is aimed at "the wrapper, the signers, and their counsel", and exists so a named human can hand it to a court. The customer therefore by design holds the linkage between address and identity — that linkage is the product. A vendor cannot simultaneously sell "we attribute governance actions to your named signer" and argue "these are just anonymous hex strings". Add voting power (a proxy for holdings), timestamps and free-text rationale, and an in-scope record set is a behavioural profile.


4. Art. 9 special-category risk

Flagged, not resolved. This is counsel's call and it must be made per-deployment, before the first seal.

The product seals, per identified person: their voting choice on each proposal, the labelled meaning of that choice, their voting power, and (under full) their free-text rationale.

Art. 9(1) covers data "revealing" political opinions. The CJEU's expansive reading in OT v Vyriausioji tarnybinės etikos komisija (C-184/20) held that data from which special-category information can be inferred by intellectual operation falls in scope. DAO governance is not party politics, but DAOs vote on grants to political causes, on jurisdictional positioning, on sanctions and censorship policy, on treasury exposure to particular states. A longitudinal record of one identified person's votes plus their written reasoning is exactly the sort of dataset from which political opinion is inferable — and, unlike an ordinary voting record, it is permanent and externally anchored. Trade-union membership and philosophical belief are conceivable in DAOs organised around labour or ideological aims.

The asymmetry that makes this worse than the usual inference argument: the assessment cannot be made retrospectively with full effect. Erasure is now available (§8), but every artefact already generated and circulated is beyond recall, and the Art. 9(2) derogations are narrow (explicit consent, or 9(2)(f) legal claims, which is at least arguable here).

(For counsel: where a DAO's proposals are manifestly political, does Art. 9(2)(e) — "manifestly made public by the data subject", and Snapshot votes are public — provide adequate cover, or is that too thin given the aggregation and permanence this product adds?)

Mitigation available today: the default hash-only content policy (§7) removes the free-text rationale from every sealed record, which substantially defuses the inference argument. The voting record itself remains.


5. Roles: controller, processor, sub-processors

Role allocation *(analysis — for counsel)*

Party Likely role Why
Deploying enterprise / legal wrapper Controller Determines the purpose — defending its signers — and the means. Owes Art. 30, Art. 35, Art. 13/14, Art. 6 lawful basis, Art. 28 contracts, Chapter V.
The DAO itself Awkward, possibly joint controller An unincorporated association or general partnership (the Ooki/Lido point) may be a joint controller with the wrapper. If it has no legal personality, liability lands on the wrapper anyway. (For counsel: can a DAO-as-general-partnership be a joint controller, and who signs the Art. 26 arrangement?)
VDA Witness (SaaS) Processor Receives and stores the full plaintext body. Needs an Art. 28 DPA with full 28(3) content, audit rights, a sub-processor clause and a deletion obligation on termination that is honest about what cannot be deleted.
Anchoring authorities Recipients of pseudonymised data, arguably not processors They receive only digests and hold no other information. That position is defensible (see §8) but must be written down and reasoned, not assumed.
The vendor of this library Neither, for a self-hosted deployment This is software you run. (For counsel: does the vendor generating a liability pack on a customer's behalf make it a joint controller for that specific purpose?)

Sub-processor / recipient register

Every third party this software contacts by default. Attach this to your Art. 30 record.

Party Endpoint (default) Receives Jurisdiction
VDA Witness https://witness.getvda.ai The full plaintext decision bodyactors, detail, reasoning, governingRule Ascertain and record. Not known to this library.
OpenTimestamps calendar A https://a.pool.opentimestamps.org 32-byte Merkle root only not documented in code
OpenTimestamps calendar B https://b.pool.opentimestamps.org 32-byte Merkle root only not documented in code
Eternity Wall https://a.pool.eternitywall.com 32-byte Merkle root only not documented in code
Catallaxy https://ots.btc.catallaxy.com 32-byte Merkle root only not documented in code
DigiCert TSA http://timestamp.digicert.com 32-byte digest in a MessageImprint US
Sectigo TSA http://timestamp.sectigo.com 32-byte digest in a MessageImprint US
Sigstore Rekor https://rekor.sigstore.dev (off by default) sha256(root), an ECDSA signature, and the operator's public key — published permanently and publicly Linux Foundation, US
Snapshot Hub https://hub.snapshot.org/graphql read-side only; but your query pattern reveals which spaces you monitor
Safe Transaction Service per chain read-side only; your query pattern reveals which Safes you monitor
Your configured JSON-RPC operator-set read-side only; your query pattern reveals which addresses you are investigating whoever you chose

State this to your DPO in these words: the anchoring authorities receive only digests. Nothing containing plaintext, wallet addresses, voting choices, proposal text or amounts reaches Bitcoin, Rekor or any TSA.

The endpoint list is a configuration decision, not a silent default: WITNESS_DAO_OTS_CALENDARS and WITNESS_DAO_REKOR_URL override it, and strict residency mode (§6) refuses anything you have not allowlisted. Rekor is off unless configured — zero-config anchoring is RFC-3161 plus Bitcoin.

Known gap: the RFC-3161 TSA list has no environment binding (opts.tsas exists in src/anchor/rfc3161.ts but nothing wires it to config), so the TSAs cannot be changed without code today. Strict residency mode will refuse them if you do not allowlist them, which is the honest failure mode, but it is not the same as being able to choose your own.


6. Transfers (Chapter V) and the residency control

What needs what

  • The plaintext leg (VDA) is unambiguously a transfer of personal data if VDA processes outside the EEA. It needs an Art. 46 mechanism — SCCs plus a transfer impact assessment addressing US government access, or reliance on the EU–US Data Privacy Framework if VDA is certified. Ascertain VDA's processing location and DPF status. This library does not know it and will not guess.
  • The digest legs are much more favourable, and the argument is set out in §8. Write it down as a short standalone memo rather than assuming it.
  • DigiCert and Sectigo are US entities. Rekor is US-operated and its content is public by design. Two of the four OTS calendars have no documented jurisdiction.

The control

Residency is now configuration, and in strict mode it is enforced at wiring time — a deployment whose endpoints breach its own declared residency does not start, rather than failing on the first request after records have already been sealed.

# EU-only mode: declare the region, enforce strictly, allowlist what you assessed.
export WITNESS_DAO_EU_ONLY=1
export WITNESS_DAO_RESIDENCY_ALLOW_HOSTS="witness.eu.example.com,.opentimestamps.org"

# Equivalent long form
export WITNESS_DAO_RESIDENCY_REGIONS=eu
export WITNESS_DAO_RESIDENCY_MODE=strict
export WITNESS_DAO_RESIDENCY_ALLOW_HOSTS="witness.eu.example.com,.opentimestamps.org"

An entry beginning with . matches that domain and its subdomains; anything else matches exactly. Comparison is case-insensitive on the hostname.

The allowlist is empty by default and there is no built-in "these hosts are in the EU" table. That is deliberate. This library does not know where witness.getvda.ai, an OTS calendar or a TSA actually processes data, and shipping a guess would be exactly the unearned assurance the rest of this codebase refuses to give. You ascertain the location, you write the host down, and the code then holds you to it. With WITNESS_DAO_EU_ONLY=1 and an empty allowlist, every endpoint is refused — including the US TSAs — which is the correct behaviour and tells you precisely which transfer decisions you still owe.

Coverage, honestly: enforcement covers the endpoints this library configures — the VDA base URL, Snapshot, the RPCs, the Safe services, the OTS calendars, Rekor, and the default TSAs. It cannot police an HTTP proxy, a DNS override, or a provider a caller constructs directly. advisory mode records the declaration and enforces nothing; it is the right setting only while the transfer analysis is still outstanding.


7. Minimisation: the content policy

Four paths carried unbounded third-party prose into permanently sealed records: a Snapshot proposal title and body, a Snapshot vote reason, a Governor proposal description, and a Governor vote reason — plus a preview of raw calldata. All were truncated for size; none was gated on content. A DAO proposal body routinely contains names, email addresses, grant-applicant details, contributor compensation, dispute narratives and occasionally accusations.

The evidentiary purpose — proving that a proposal existed bearing given text — is fully served by a digest, which the providers already computed and then sealed the plaintext alongside anyway.

WITNESS_DAO_CONTENT_FREETEXT=hash-only   # default
WITNESS_DAO_CONTENT_MAX_CHARS=4000       # cap under `full`
Mode Sealed Trade-off
full text (capped) + digest + length Richest evidence. Irreversible exposure of arbitrary third-party text.
hash-only digest + length, no text Default. Tamper-evidence and re-derivability preserved; a report cannot reproduce the text. Hold the plaintext in your own erasable store, keyed by the digest.
omit nothing Maximum minimisation. The record cannot demonstrate anything at all about the text, including that it was unaltered.

The trade-off, stated plainly. hash-only weakens evidentiary richness: a pack can prove a proposal body existed and was not altered given the plaintext, but cannot itself show what it said. In exchange it removes the single largest irreversible exposure in the product. That is why it is the default — it is the only default that is defensible under Art. 5(1)(c) without an operator making a decision — and why the mode is itself sealed into each record as detail.freeTextPolicy, so a reader can tell "minimised by policy" from "there was nothing there".

Digests always cover the full text, never the truncated excerpt, so they stay comparable across a policy change.

Operators who want plaintext with their own scrubbing can run full and inject a redactFreeText function on the provider; it runs before anything is measured, digested or sealed. Note that the digest then commits to the redacted text. This is not a PII detector and does not pretend to be: a redactor that works 95% of the time on permanent records is worse than a digest that works every time.


8. Retention and erasure

The architectural fact everything rests on

Only digests leave the building. Verified line by line:

  1. MultiAnchorer.anchorRecords() builds a Merkle tree over record bodyHash values and anchors only the root. Per-record inclusion proofs are retained locally, not published.
  2. OpenTimestamps receives the raw 32-byte root. What eventually lands in a Bitcoin transaction is an aggregated commitment several hash operations removed from our root.
  3. RFC-3161 puts the root in a MessageImprint. The TSA returns a token; nothing of ours is published.
  4. Rekor — the only genuinely public, permanent, indexed publication — publishes sha256(root), an ECDSA signature over the root, and the operator's public key. Nothing else. It is off by default.

The only party receiving plaintext personal data is VDA Witness. That single fact converts the erasure problem from catastrophic to manageable.

Is an anchored digest personal data? *(For counsel — this is the pivotal question)*

A bodyHash is SHA-256 over a canonical JSON body containing an address, a vote and a timestamp. Under Art. 4(5) that is textbook pseudonymisation, not anonymisation: the preimage exists. WP29 Opinion 05/2014 is explicit that hashing is pseudonymisation and that hashing a value from a small, guessable domain is vulnerable to brute force.

Two features make the position here materially stronger than the generic worry:

  • What is anchored is a Merkle root, not a per-record hash. Brute-forcing it requires guessing the complete leaf set and its order — computationally hopeless, and structurally different from hashing a single email address.
  • The preimage domain is not guessable. A bodyHash preimage is a canonical JSON document containing recordId, seq, sealedAt, chainKey, the full decision including a long reasoning string, and governingRule with full ruleText. It is a large document with high-entropy fields, not a 42-character address in a 2^160 space.

The honest position: anchored roots are, at worst, pseudonymised personal data whose re-identification is computationally infeasible without the preimage, and are arguably anonymous in the hands of the anchoring parties, who hold no other information and have no reasonable means to obtain any (the Breyer / EDPS v SRB "reasonable means" test applied to the recipient).

Crypto-shredding: the design

Destroy the preimage and the anchored root becomes an unlinkable, uninvertible 32-byte value. Several European supervisory authorities, and the EDPB's 2025 blockchain guidance, treat this family of argument as the viable route for immutable ledgers provided only digests were ever published — which is exactly this architecture.

witness-dao erase --record rec_01H... --reason "Art.17 request REQ-2026-0142" --confirm
witness-dao erase --list

--confirm is mandatory; there is no undo and no backup is taken. The reason must be a reference (a ticket id, a request number) — the CLI refuses a reason that looks like a wallet address, because putting the subject in the reason defeats the erasure.

What is destroyed: the entire record body — decision (actors, choices, voting power, free text), reasoning, governingRule including the rule text.

What survives, and why:

Retained Why
bodyHash The Merkle inclusion proof operates on it; without it the record cannot be shown to be in the anchored window at all. Not a preimage.
prevHash Hash-chain continuity: the successor's check compares against it.
seq, chainKey Position in the chain.
signature, signedBy The record remains attributable to a signing key.
sealedAt When it was sealed.
anchorState Anchor linkage.

What a tombstoned record still proves: that a record with that digest occupied that position in that chain at that time, sealed under that key, inside that anchored window. What it no longer proves: what it said.

What erasure does to verification

A tombstone is missing data, not tampering, and the verifier says so:

  • The tombstoned record verifies as INSUFFICIENT_PROOF, never BROKEN, with reason body_not_canonicalisable: RECORD_TOMBSTONED ….
  • A chain containing a tombstone cannot be walked past it, so the chain also reports INSUFFICIENT_PROOF. Continuity is not disprovedprevHash and bodyHash are retained and a reader can check them by hand — but the verifier will not assert a continuity it could not walk.
  • Merkle inclusion against the anchored root still verifies, because it operates on bodyHash.

This works through offlineVerify's documented signedBodyExtractor seam (tombstoneAwareSignedBody), which every report and verify path in this package installs by default. A third-party verifier that does not install it will report BROKEN. That is why the tombstone marker lives inside the record (witnessDaoErasure) rather than beside it, and why it is called out here: if you hand a tombstoned bundle to an external verifier, tell them.

The remote half — an honest gap

The VDA Witness API exposes no delete, redact or expire operation. witness-dao erase therefore does two things and not a third:

  1. It destroys the local plaintext in the seal journal (the journalled failure record, which holds a complete SealRequest, is deleted outright — nothing was sealed, so there is no envelope worth keeping).
  2. It records a standing erasure directive that is applied to every record set this tool handles from then on, including records re-fetched from the SaaS, before they reach a report, a renderer or an MCP result. Local enforcement is complete.
  3. It does not delete the SaaS copy. The tombstone records this as remote: "not_supported", the CLI exits 4 (incomplete) and says so, and every report over an affected window carries a caveat stating that erasure is local only.

The interface the missing capability would need is specified as RemoteRecordEraser in src/seal/witness-client.ts. Raise the deletion with VDA under your Art. 28 contract and record the outcome. Do not represent an erasure as complete until the processor confirms it in writing.

Retention and purge

The seal journal accumulates every voter address, choice, voting power and free-text reason the pipeline has ever touched, on your own disk, indefinitely, and invisibly to your normal data-lifecycle tooling. Art. 5(1)(e) applies to that copy just as it does to the SaaS. It is also the one copy you can unilaterally delete.

export WITNESS_DAO_RETENTION_DAYS=730
witness-dao purge --dry-run          # always do this first
witness-dao purge --confirm

Safe to run: the records live upstream and are re-fetchable, and every seal request carries a deterministic decisionId, so an event re-observed after its journal entry is purged is deduplicated upstream rather than sealed twice. What is lost is the local memory of which events were already handled. Tombstones are never purged — they hold no personal data by construction and they are the evidence that an erasure took place. Entries with an unparseable timestamp are retained, not deleted: failing towards deletion because a date could not be read is the wrong direction.

WITNESS_DAO_PURGE_LOCAL_STATE=0 disables purging entirely on a given host, so a purge cannot be run by accident on a machine that is not the one holding the retention decision.

Also in scope for your retention schedule, and not covered by purge: anchor-runs.json (proof material, no personal data, and the only copy — back it up), dossier-access.log (see §11), erasures.json (record ids and your reason references), and any report artefacts written with --out.

Art. 17(3)(e) — the strongest card

Art. 17(3)(e) — retention necessary "for the establishment, exercise or defence of legal claims" — is precisely this product's stated purpose. The liability-defence pack exists for no other reason. Post-Ooki and post-Lido the prospect of claims against DAO participants is concrete rather than speculative, which is what the exemption requires. Records concerning a person who was a multisig signer or an active voter, retained for the applicable limitation period, look like a textbook (e) case.

Art. 17(3)(b) — compliance with a legal obligation — is weaker but available where the wrapper has a statutory record-keeping duty (an authorised CASP under MiCA Art. 68, an AML-obliged entity under AMLD5/6 with its five-year retention, corporate record-keeping under Wyoming DAO LLC law).

But the exemptions are narrow, purpose-bound and evidence-hungry. They will not cover retention beyond the applicable limitation period; free-text proposal excerpts, which are not necessary to establish who did what (hence the hash-only default); data about voters not plausibly connected to any claim; or continued retention once a claim is resolved and time-barred. "We keep everything forever because litigation" will not survive scrutiny.

To rely on Art. 17(3)(e) you need, in writing, before the first seal:

  1. the specific claim types anticipated;
  2. the applicable limitation periods per jurisdiction (Wyoming, RMI, N.D. Cal., relevant EU states) with a derived retention period — this is what goes in WITNESS_DAO_RETENTION_DAYS;
  3. a data-category-by-category necessity analysis: addresses and votes, plainly; a 4,000-character proposal excerpt, much less obviously;
  4. a review trigger and a deletion procedure for when the basis lapses — witness-dao purge and witness-dao erase are the mechanisms, but the trigger is yours;
  5. a documented response template for erasure requests, explaining what can and cannot be erased, what a tombstone retains, and the Art. 21 objection route.

9. Rectification and supersession

Art. 16 gives a right to rectification and Art. 19 requires the controller to communicate it to each recipient. A sealed record cannot be rewritten — correctly, since evidence is append-only — and the recognised mitigation for an immutable ledger is append-correction with propagation. The product did the append and skipped the propagation: a record known to be wrong stayed in every future report with no marker at all.

A record may now carry, in its signed decision.inputs.detail:

{ "supersedes": { "recordId": "rec_older", "reason": "Safe API returned a stale executor" } }

Because it rides in detail, it is inside the canonical body that bodyHash digests and the signature covers, so a correction cannot be forged, retracted or attached after the fact. It is not a new event kind, because the event-kind union is a trust-critical closed set that a reporting concern has no business widening.

Both report builders read it and propagate it:

  • superseded records are marked [SUPERSEDED by …] inline in the findings table, not just in a list at the top — a correction the reader has to hunt for is not visible;
  • EvidenceLine.supersedes / .supersededBy and ParticipationFinding.supersedes / .supersededBy carry it in the JSON;
  • a caveat names each superseded record and the record correcting it;
  • a dangling pointer — "this record corrects something you were not given" — is reported too, so a correction cannot be neutralised by withholding its target.

This does not make Art. 16 "satisfied". It converts an Art. 16 "impossible" into an Art. 16 "answered by visible annotation", which is a much better conversation to have with a supervisory authority. Art. 19 communication to recipients who already hold a rendered artefact remains contractual and procedural, not technical: a report in counsel's hands cannot be recalled.


10. Art. 14 notice: the structural problem

The product cannot solve this and does not claim to.

SnapshotProvider.listEvents enumerates every vote on every in-scope proposal. SafeProvider pages the Safe Transaction Service for every multisig transaction and confirmation. Neither the voter nor the signer is your customer. Neither is asked. Neither is told.

Where personal data is not obtained from the data subject, Art. 14 requires the controller to provide identity, purposes, legal basis, recipients, transfer information, retention period and rights — within a month. You will be processing data about potentially thousands of voters you have no channel to.

Art. 14(5)(b) excuses notice where it "proves impossible or would involve a disproportionate effort", and the recital contemplates a public-notice substitute. That is genuinely arguable for anonymous token-holders. But: (i) it is an exemption that must be assessed and documented, not assumed; and (ii) it is much weaker for the small set of named multisig signers, who are identifiable, reachable, and whose data is processed most intensively — and who are precisely the people the product exists to defend.

What the deploying enterprise must do:

  1. Publish a layered privacy notice in the DAO forum and link it from the governance rules directory (that directory is already the canonical place your DAO looks for governance documents).
  2. Produce an Art. 14(5)(b) assessment memo distinguishing the anonymous-voter case from the named-signer case. Do not treat them alike.
  3. For named signers, give direct notice. You know who they are and you can reach them.
  4. Decide the lawful basis. Art. 6(1)(f) legitimate interests with a documented LIA is the likely route; the balancing test is materially different for "defending our own signer" than for "monitoring everyone who votes in this DAO".

(For counsel: for the named signers whose personal liability the product defends, is notice plus a documented Art. 6(1)(f) LIA sufficient, or does the wrapper need something closer to consent given the permanence?)


11. The dossier problem

buildLiabilityDefenceReport takes a subject address and produces a complete behavioural profile: what they voted on, what they did not, when, with how much weight, and (under full) their written reasons. Nothing checks that the subject consented, that the subject is the requester, or that the purpose is defensive rather than investigative. The identical call builds a dossier on a rival signer, a departing contributor, or anyone whose address is known. Under Art. 6(1)(f), defending your own signer is a strong LIA; building a file on a third party is not — and nothing distinguished the two, recorded which was intended, or left a trail.

Three controls now ship. None of them makes the processing lawful; they make it reviewable.

1. Purpose is mandatory.

witness-dao report liability --dao ens.eth --subject 0xabc… \
  --purpose "Defence of signer in matter 2026-114"

--purpose is a required flag, and purpose is a required MCP tool argument. It is written into report.purpose and rendered at the top of the artefact. A pack built by a direct library call without one carries a NO PURPOSE RECORDED caveat.

2. Every generation is logged. <state-dir>/tenants/…/dossier-access.log, one JSON object per line: timestamp, DAO, subject, purpose, surface (cli or mcp), account id and OS user where available. A controller can then answer "who ran a pack on whom, and why". If the log cannot be written, the report still runs — you are entitled to it — but the failure is reported as a problem and the run exits 4.

Note that this log is itself personal data about both the subject and the operator. Include it in your retention schedule; witness-dao purge does not touch it.

3. The artefact says what it is. Every pack opens with a "What this document is, and what it contains" section stating that it is a behavioural profile of an identified natural person, that addresses linked to a named individual are personal data in substance, that it is designed for the establishment/exercise/defence of legal claims, and that use for third-party profiling is outside the product's design.

The MCP surface

liability_defence_report is registered with risk: 'export' and is disabled unless WITNESS_DAO_MCP_ALLOW_WRITES=1. MCP over stdio is unauthenticated by design — the host process is the authorisation boundary — and this product's own threat model has attacker-authored proposal text reaching the agent's context through ingest_governance_events. A live prompt-injection path into a tool that exports a named person's dossier is not hypothetical.

The tool description now states that the output is personal data, that calling it pulls a behavioural profile into the conversation transcript and any model-provider retention behind it, that it must not be forwarded or retained without a lawful basis, and that the agent must pass the requesting human's own stated reason rather than inventing one.

(For counsel: where the subject is not the requester, does the customer owe the subject an Art. 14 notice for the pack specifically, separate from the ingestion notice in §10?)


12. Metadata leakage

RFC-3161 requests use plaintext HTTP. The defaults are http://timestamp.digicert.com and http://timestamp.sectigo.com. This is conventional — the token is signed, so integrity does not depend on TLS — and the code independently checks the nonce echo and the messageImprint, so the cryptographic position is sound.

The data-protection angle is narrow but real: a network observer sees which digests you timestamp, when, and how often. That is anchoring cadence and volume metadata, plus a correlatable digest that could later be matched against a published Rekor entry. No personal data is exposed. Prefer https:// where the TSA supports it; both DigiCert and Sectigo do.

Two related read-side leaks worth recording in your DPIA: your Snapshot and Safe query patterns reveal which spaces and Safes you monitor, and your JSON-RPC query pattern reveals which addresses you are investigating — to whoever operates the RPC endpoint you chose.


13. DPIA input pack

An Art. 35 DPIA is near-certainly required. On the EDPB's own criteria this hits four or five against a threshold of three:

  • Evaluation or scoring — the evidence-strength grading of an individual's conduct.
  • Systematic monitoring — continuous ingestion of all governance activity.
  • Data processed on a large scale — potentially every voter in a DAO.
  • Matching or combining datasets — Snapshot + Safe + on-chain + git rule history.
  • Legal or similarly significant effect — the product's explicit selling point is that its output bears on personal legal liability.

Technical facts to paste into the assessment

Question Answer
What personal data? §2
Whose? Voters, multisig signers, proposal authors, transfer recipients — mostly not your customers
Retention? Configured in WITNESS_DAO_RETENTION_DAYS; you must derive it from a limitation-period analysis (§8)
Recipients? §5 register
Transfers? §6
Erasure possible? Locally yes (crypto-shredding, §8); SaaS side not yet
Rectification possible? By append-correction with propagation, §9
Automated decision-making (Art. 22)? No. The product produces evidence a human interprets; it makes no decision about any person
Security TLS to the SaaS; state files 0600 in 0700 directories, atomic and fsynced; API key never logged, never written to a report, never accepted from a config file; egress default-deny
Special categories Possible by inference; §4
Criminal-offence data (Art. 10) Not processed. Do not start — see governance-rules/treasury.transfer.md

Risks to assess explicitly

  1. Irreversibility. Mitigated but not eliminated by crypto-shredding. Artefacts already circulated cannot be recalled.
  2. Art. 9 inference (§4) — must be assessed per-DAO before the first seal.
  3. Third-party data subjects (§10) — the structural Art. 14 problem.
  4. Profiling capability (§11) — the dossier can be built about anyone.
  5. Public permanence via Rekor — if you enable it, sha256(root) and your public key are published permanently and publicly.
  6. Sanctions-screening scenario — the worst case this product could produce; see governance-rules/treasury.transfer.md.
  7. Chapter V for the plaintext leg (§6).

14. Art. 30 record template

Complete and retain. Nothing below is filled in for you, because every entry is a controller decision.

CONTROLLER
  Name / contact / DPO:                    ____________________
  Joint controller (DAO / wrapper?):       ____________________  [Art. 26 arrangement: ____]

PURPOSES OF PROCESSING
  [ ] Establishment, exercise or defence of legal claims (the product's design purpose)
  [ ] Demonstrating governance process to an auditor or supervisor
  [ ] Other: ____________________

LAWFUL BASIS (Art. 6)
  [ ] 6(1)(f) legitimate interests   -> LIA reference: ____________________
  [ ] 6(1)(c) legal obligation       -> the obligation: ____________________
  [ ] Other: ____________________
  Art. 9 assessed?  [ ] yes -> outcome: ____________  [ ] no -> DO THIS BEFORE THE FIRST SEAL (§4)

CATEGORIES OF DATA SUBJECT
  [ ] DAO voters (approx. count: ____)   [ ] Multisig signers (count: ____)
  [ ] Proposal authors                   [ ] Treasury transfer recipients

CATEGORIES OF PERSONAL DATA
  Copy the table in §2 of DATA-PROTECTION.md. Record the content policy in force:
  WITNESS_DAO_CONTENT_FREETEXT = ____________  (default hash-only)

RECIPIENTS
  Copy the register in §5. Record for each: contract reference, transfer mechanism, date verified.
  VDA Witness processing location: ____________  DPA reference: ____________
  DPF certified?  VDA: ____  DigiCert: ____  Sectigo: ____

THIRD-COUNTRY TRANSFERS (Chapter V)
  Plaintext leg (VDA):   mechanism ____________  TIA reference ____________
  Digest legs:           memo reference ____________ (see §8 for the argument)
  Residency mode in force: ____________  Allowlist: ____________

RETENTION
  Period: ______ days   Derived from: ____________________ (limitation-period analysis, §8)
  WITNESS_DAO_RETENTION_DAYS = ______   Purge schedule: ____________
  Review trigger: ____________________

SECURITY MEASURES (Art. 32)
  See the DPIA table in §13. Additional organisational measures: ____________________

DATA SUBJECT REQUEST PROCEDURE
  Erasure:        `witness-dao erase` + processor request. Owner: ____________
  Rectification:  append-correction (§9). Owner: ____________
  Access:         ____________________
  Response template reference: ____________________

15. Configuration reference

Variable Default Effect
WITNESS_DAO_CONTENT_FREETEXT hash-only full | hash-only | omit — how third-party free text is sealed (§7)
WITNESS_DAO_CONTENT_MAX_CHARS 4000 Cap on any field sealed verbatim under full
WITNESS_DAO_EU_ONLY off Shorthand for regions=eu, mode=strict
WITNESS_DAO_RESIDENCY_REGIONS none Declared processing regions, comma-separated
WITNESS_DAO_RESIDENCY_MODE advisory strict refuses non-allowlisted endpoints at startup
WITNESS_DAO_RESIDENCY_ALLOW_HOSTS empty Host allowlist; .example.com matches subdomains
WITNESS_DAO_RETENTION_DAYS none Age after which purge evicts journal entries
WITNESS_DAO_PURGE_LOCAL_STATE 1 Set 0 to forbid purge on this host

Equivalent config-file keys: contentPolicy: { freeText, maxFreeTextChars }, residency: { regions, mode, allowedHosts }, retention: { maxAgeDays, purgeLocalState }. Secrets are still refused in config files, always.

Commands: witness-dao erase, witness-dao purge, witness-dao report liability --purpose … [--participant-set <file>]. Run witness-dao <command> --help for the full text.


16. What is still missing

Documented honestly, because this is the file where that matters most.

Implemented in code

  • Crypto-shredding with tombstones, and complete local enforcement of the directive (§8)
  • Retention policy and witness-dao purge (§8)
  • Content policy defaulting to digest-only (§7)
  • Enforced residency allowlist and EU-only mode (§6)
  • Supersession, propagated into both report types (§9)
  • Merkle commitment over the participant set, replacing the incentive to seal the voter roll (§8 of the README)
  • Purpose capture, access logging and MCP gating on the dossier path (§11)

Documented only — the deploying enterprise must supply these

  • The lawful-basis determination and the LIA
  • The DPIA itself (§13 is input, not output)
  • The Art. 30 record (§14 is a template)
  • The limitation-period analysis that turns "retention" into a number
  • The Art. 28 DPA with VDA, with a named sub-processor list and change notification
  • SCCs / DPF reliance and a transfer impact assessment for the plaintext leg
  • The layered privacy notice and the Art. 14(5)(b) assessment
  • Ascertaining where VDA, and the OTS calendars, actually process data

Genuinely not solved

  • No SaaS-side deletion. The remote half of erasure is an interface (RemoteRecordEraser), not a capability. The gap is stated at the point of use, in the tombstone, and in every affected report.
  • A third-party verifier without tombstoneAwareSignedBody reports BROKEN for a tombstone. The marker is in the record, but you must tell them.
  • No non-inclusion proof. The participant-set commitment supports inclusion proofs; demonstrating absence still requires producing the whole roll.
  • No RFC-3161 TSA environment binding, so the TSAs cannot be reconfigured without code (§5).
  • RFC-3161 over plaintext HTTP leaks anchoring cadence (§12).
  • Art. 19 propagation to already-circulated artefacts is procedural, not technical (§9).
  • Nothing here anonymises the on-chain source data. Snapshot votes and Safe transactions are public and permanent independently of this product. Erasing our copy does not erase theirs, and no claim otherwise should be made to a data subject.

Cross-references: README.md (what the product is), LIMITATIONS.md (what it does not do), RUNBOOK.md (operating it), governance-rules/treasury.transfer.md (the sanctions-screening warning).