The workflow
A model arrives untrusted from one hospital and leaves as a certified base model. Step by step:
- Register an institution; its first account is the institution's admin. Colleagues join with an invite code, an approved email domain, or after an admin approves them.
- Stand up a node: generate an Ed25519 key, post the public half, sign the challenge. A site that completed this is an independent installation in the metrics.
- Submit a bundle — weights, a Mitchell-style model card, an evaluation report, an optional clinician-readable fine-tuning manual, and the parent it was derived from — with a quote the site signed over a measurement of the code that ran.
- Automated gate: seven checks (card completeness, metadata, lineage attestation, metrics, subgroup gaps, membership-inference leakage, parameter norm). A failing check blocks the case with the reason on the decision log.
- Review board: reviewers from other institutions sign approve / reject / block. A reviewer from the owning institution is refused. Certification needs k approvals from distinct institutions, including the technical and clinical composition the charter sets.
- Certified base: the release gets a citable identifier naming every contributor and reviewer. Anyone registered may download it and fine-tune it; derived models link to their parent, so lineage verifies back to the root.
- Reciprocity: to receive a multi-site evaluation, a site serves as evaluator for others. Only acknowledgements signed by the counterparty count.
Run it
pip install -e ".[hub,dev]"
openmed init --data-dir ./openmed-data --institution "University of Miami" --email admin@example.org
openmed serve --data-dir ./openmed-data --port 8000
Open http://127.0.0.1:8000; the JSON API is documented at /docs. To see every workflow populated with synthetic data, openmed seed-demo --data-dir ./demo-data first. From a site:
openmed register --hub https://hub.example.org --institution "Somewhere Medical Center" --email you@somewhere.org
openmed node keygen && openmed node register
openmed measure --script train.py # the digest a maintainer approves
openmed submit --name decline-risk --version 1.0.0 --weights model.npz \
--card card.json --evaluation eval.json --manual manual.json --script train.py
Attestation without hardware
A hardware TEE measures the loaded code and signs the digest with a key the host cannot
reach. Without hardware, the Hub does the next best thing, and says so. In the default
nodekey mode, openmed submit measures the installed package, the
training script and any extra files, requests a single-use challenge, and signs
measurement + config hash + nonce with the node key that completed the handshake. The Hub
holds only the public key, checks the signature, the freshness, the challenge binding, and
that the measurement is on the allow-list maintainers publish.
What it proves
The holder of that site's key vouched for this code digest, now, for this challenge. The Hub cannot forge it; a patched pipeline measures differently and is refused.
What it cannot prove
Anything about a site whose operator lies: the operator holds the key. That residual risk is what Byzantine-resilient merging and multi-site evaluation are for.
Upgrading later
A TEE backend replaces the node key with a hardware root of trust behind the same Attestor interface. Nothing else in the Hub changes.
Account security
The Hub decides who may act for an institution, so its accounts are guarded accordingly.
- Passwords: PBKDF2-HMAC-SHA256 with a per-user salt; at least ten characters, not your email or name, not a common password.
- Two-factor authentication: TOTP (RFC 6238) with any authenticator app, plus ten single-use recovery codes. It is required for reviewers, maintainers and admins: signing a review, granting a role or approving a pipeline measurement is refused until it is enabled.
- Sessions: HttpOnly, SameSite=Lax cookies (Secure behind HTTPS), signed with the server secret and bound to a per-user security stamp. Changing the password or the second factor rotates the stamp and signs every other session out.
- Throttling: per-address rate limit on sign-in, and an account lock that doubles after each failure past the threshold, capped at fifteen minutes.
- CSRF: every HTML form carries a double-submit token that a cross-site page cannot read.
- Membership: joining an institution needs its invite code, an email in a domain it approved, or an institution admin's approval. Until then the account can look but not act, so a stranger cannot remediate, appeal, download or evaluate in an institution's name.
- API tokens: 256-bit random, stored only as SHA-256 hashes, revocable on the account page.
- Headers: Content-Security-Policy, X-Frame-Options, nosniff, Referrer-Policy, and HSTS behind HTTPS.
- Audit log: sign-ins and failures, lockouts, second-factor changes, token and role changes, member approvals, measurement approvals and node verifications, with the client address; visible to admins.
Not yet: email verification and self-service password reset (both need an outgoing mail service; an institution admin re-enables an account today), hardware security keys (WebAuthn), and single sign-on. Put the Hub behind TLS; it does not terminate it itself.
What is and is not enforced
- Reviews signed through the web form use a key the Hub holds for the reviewer; the record says so. A reviewer who registers a client-held key signs locally and the Hub only verifies, so it cannot mint that reviewer's approval.
- Evaluation acknowledgements are signed with a per-institution service key the Hub holds, on the requester's explicit action.
- Dispute actions are recorded with the acting account and
actor_authenticated: falseon the ledger: the session was authenticated, the ledger entry itself carries no signature. - Every publish, review, dispute, certification and credit event is on one of three hash-chained ledgers;
/api/v1/ledgers/verifychecks them.