- Docs
- Bureau — Blue Team (defensive)
- Trial-Seal
Bureau — Blue Team (defensive)
Trial-Seal
Every patient observation is signed at the bedside device that captured it. A chain-of-custody runs from site through CRO and sponsor to FDA. Selective post-hoc patient deletion is detectable because every visit is a Merkle leaf that cannot be removed without breaking the published chain.
Posture: 🔵 Blue Team (defensive) · Status: alpha
What it does
Clinical-trial data integrity has historically depended on procedural controls rather than cryptographic ones. A sponsor may drop patients from a dataset before submission, change the analysis model from the one in the Statistical Analysis Plan (SAP) to a different one, leak patient data into LLM training corpora in violation of HIPAA, or break the chain-of-custody between the CRO (Contract Research Organization) and the sponsor. By the time the FDA reviewer sees the package, these alterations are typically not visible from the submitted record alone.
Trial-Seal addresses this class of risk cryptographically. Four signed shapes form the system. Every PatientObservation is signed at the bedside device that captures the visit (a tablet or instrument) and includes the trial id, hashed subject id, visit number, per-measurement digests, and observation status (active, withdrew, completed). Each CroChain leg signs a hop in the structurally-fixed site → CRO → sponsor → FDA chain with prevDigest linking. The SapManifest is the signed Statistical Analysis Plan – the sponsor commits to a specific analysis-model digest before unblinding. A TrialSealProof is published when any of four contradictions are detected.
Who would use it
- A sponsor (pharma company) that wants its trial data to be FDA-grade unfalsifiable from day one.
- An FDA reviewer who needs a reviewer-side verifier independent of the sponsor.
- A CRO that wants to differentiate on cryptographic data integrity.
- A DSMB (Data Safety Monitoring Board) overseeing an interim analysis without trusting either CRO or sponsor.
- A patient-advocacy group or investigative journalist auditing a published trial post-approval.
What you'll need
- The Pluck CLI (
npm install -g @sizls/pluck-cli). - Bedside devices with signing keys. The Pluck reference implementation runs on iPad and Android tablets via the mobile reader app; production deployments use device-attested keys (Apple Secure Enclave, Android Keystore).
- A registered SAP signing key for the sponsor. The sponsor commits to the analysis-model digest before unblinding.
- Custody-chain signing keys at each hop (site investigator, CRO, sponsor, FDA-routing).
- For verifiers: only the Rekor entries plus the trial-registry id (ClinicalTrials.gov NCT number).
Step-by-step
The alpha runs the full constraint chain on synthetic patient observations, custody legs, SAP manifests, and submissions – there is no live bedside-device daemon yet. Production capture and verify ship in a follow-up. To exercise the system today:
pluck bureau trial-seal demo
Expected output: the system ingests five signed PatientObservations, one SAP manifest, a partial Custody chain (site and CRO present; sponsor and FDA missing), and a submission view that deletes Subject-005 and deploys a divergent analysis model. Three signed proofs emit (patient-deletion, sap-divergence, chain-broken). Each proof carries the offending observation digest, the SAP-manifest binding, and the custody legs.
What to do with the output: in production every bedside visit signs at the moment of capture; the CRO daemon signs the chain hop at intake; the sponsor signs at submission; and the FDA reviewer's verifier checks the entire dossier from Rekor before review. A patient-deletion proof is verifiable evidence of post-hoc dataset alteration; a sap-divergence proof flags an analysis-model substitution; a training-leak proof flags a HIPAA-relevant contamination event.
Run it yourself
Drop this into a Node 18+ project (npm install @sizls/pluck-bureau-trial-seal @sizls/pluck-bureau-core tsx):
// index.ts
import { createHash } from "node:crypto";
import {
createTrialSealSystem,
fingerprintPrivateKey,
signCanonicalBody,
} from "@sizls/pluck-bureau-trial-seal";
import { generateOperatorKey } from "@sizls/pluck-bureau-core";
const sha256 = (s: string) => createHash("sha256").update(s).digest("hex");
const flush = (n = 60) => new Promise<void>((r) => { let i = 0; const tick = () => (++i >= n ? r() : setImmediate(tick)); setImmediate(tick); });
async function main() {
const op = generateOperatorKey();
const sponsor = generateOperatorKey();
const sponsorFp = fingerprintPrivateKey(sponsor.privateKeyPem);
const system = createTrialSealSystem({
signingKey: op.privateKeyPem,
disablePausePoll: true,
disableLogging: true,
});
// One signed SAP manifest committing the analysis-model digest.
const trialId = "NCT04567890";
const sapBody = {
schemaVersion: 1 as const, trialId, version: "v1.0",
analysisModelDigest: sha256("analysis-model:disclosed:v1.0"),
observedAt: "2026-04-26T00:00:00.000Z",
observerFingerprint: sponsorFp,
};
const manifestId = sha256(JSON.stringify(sapBody));
const sapSig = signCanonicalBody({ ...sapBody, manifestId }, sponsor.privateKeyPem);
try {
system.recordManifest({ ...sapBody, manifestId, signature: sapSig.signature });
// FDA submission deploys a divergent analysis model -> sap-divergence fires.
system.updateSubmissionView({
submittedSubjectHashes: { [trialId]: [] },
deployedAnalysisModelDigest: { [trialId]: sha256("analysis-model:swapped") },
trainingLeakSubjectHashes: {},
});
await flush();
for (const p of system.facts.proofs()) {
console.log(`proof kind=${p.kind} id=${p.proofId.slice(0, 16)}…`);
}
} finally {
await system.shutdown();
}
}
main().catch((err) => { console.error(err); process.exit(1); });
Run with tsx index.ts. Expected output:
proof kind=sap-divergence id=…
▶ Open in StackBlitz – runs in your browser, no install required.
What you get
A signed TrialSeal.Proof with one of four kind values:
patient-deletion– a previously-signed observation no longer appears in the submitted dataset and the missing patient was not coded as a withdrawal.sap-divergence– the analysis-model digest in the submission does not match the latest signedSapManifestdigest.training-leak– the Mole composition detected trial data was used to train a downstream LLM.chain-broken– a custody hop is missing (sponsor or FDA leg never signed).
The Bureau never carries raw PHI. Subject identities are hashed (sha256(trialSalt + subjectId)). Per-measurement digests bind observations to specific lab values without ever lifting the values themselves into the signed body.
What it can't do
- Trial-Seal protects integrity, not interpretation. A trial can still be poorly designed; Trial-Seal only ensures the data and analysis you submit match what you committed to.
- A compromised bedside device with a stolen signing key can sign fabricated observations. Device-attested keys (Secure Enclave, Android Keystore) and multi-party site signing raise the bar.
- The system cannot detect a sponsor who never enrolled the patients in the first place. Trial-Seal protects against post-hoc deletion, not against fabricated enrollment. Pair with site-monitor attestation.
training-leakdetection depends on Mole's adversarial extraction probes, which have a non-trivial false-positive surface. Treat training-leak as a strong signal requiring follow-up, not a finding.
A real-world example
A mid-stage pharma company runs a Phase 3 trial of a novel oncology drug across 32 sites in 6 countries via a global CRO. Each bedside tablet signs every visit at the moment of capture. The CRO's daemon signs each batch at intake. The sponsor commits the SAP manifest two weeks before unblinding. At submission, an FDA reviewer's Trial-Seal verifier checks the dossier and finds: every committed observation appears in the submission, the deployed analysis-model digest matches the SAP commitment, the custody chain runs cleanly from each site through the CRO to the sponsor to the FDA submission node. The reviewer accepts the package without the usual rounds of source-data verification – the math has already done the work. The sponsor's submission cycle shrinks by months; the reviewer's confidence is higher than under traditional manual SDV.
For developers
Predicate URIs
| URI | What it attests |
|---|---|
https://pluck.run/TrialSeal.PatientObservation/v1 | Per-visit signed observation (bedside device) plus measurement digests. |
https://pluck.run/TrialSeal.CroChain/v1 | Per-leg site → CRO → sponsor → FDA custody hop. |
https://pluck.run/TrialSeal.SapManifest/v1 | Signed Statistical Analysis Plan plus analysis-model digest commitment. |
https://pluck.run/TrialSeal.Proof/v1 | Published proof with kind (patient-deletion, sap-divergence, training-leak, chain-broken). |
Programs composed
- Custody – site → CRO → sponsor → FDA chain.
- Mole – training-leak detection (HIPAA-grade LLM contamination).
- Fingerprint – analysis-model digest verification against signed SAP.
- Rotate – PI (Principal Investigator) key compromise / rotation without retroactive invalidation.
Threat model + adversary
The adversary is the sponsor with strong incentives to massage data, the CRO that wants to keep its biggest client happy, and (in the training-leak case) a downstream AI vendor that may have ingested PHI. See Threat Model.
Verify a published cassette
pluck bureau verify <bundle-dir>
cosign verify-blob --key <pubkey.pem> --signature <sig> --type https://pluck.run/TrialSeal.Proof/v1 <body.json>
Every proof is a DSSE envelope notarized to Rekor. FDA reviewers, DSMBs, and patient advocates verify a proof's signature chain against the bedside device's published key fingerprint, re-derive the chain-of-custody digests, confirm SAP-manifest binding, and check submission membership – all from public data plus the public ClinicalTrials.gov NCT id. No sponsor or CRO cooperation required.
See also
- Bureau Foundations
- Threat Model
- Verify a dossier
- Custody – chain-of-custody primitives
- Mole – adversarial training-data extraction probes (training-leak detection)
- Fingerprint – analysis-model digest verification
- Rotate – PI key compromise / rotation