Skip to content

Institutional Crypto Custody

**FinTech · High-value · Full key lifecycle management**

Overview

Institutional Crypto Custody

FinTech · High-value · Full key lifecycle management

The problem

A custody firm holds $5B+ in crypto assets across dozens of chains for pension funds, corporate treasuries, and ETF issuers. The key management practice is:

  • Multi-sig wallets with 3-of-5 or higher thresholds, co- signers spread across geographies and HSMs.
  • Quarterly key rotation required by internal controls.
  • Emergency rotation when a co-signer leaves, a device is compromised, or a jurisdiction-specific event requires it.
  • Post-incident forensics is often “screenshot of the multi-sig dashboard at the time.”

The pain points:

  1. Rotations are manual and fragile. An errant key not rotated properly becomes a permanent liability, or a ticking time bomb when someone’s HSM quietly fails.
  2. Recovery is an emergency. Lost keys = lost funds. Wallet providers offer “social recovery” but with proprietary flows and questionable guarantees.
  3. Audit trails are shallow. “This $100M transfer was signed by these three keys on this date” has to be reconstructed across multiple systems.
  4. Cross-jurisdiction coordination is hard. EU and US subsidiaries each have their own HSMs and approval rules; moving funds between them requires reconciling two different workflows.

Why Quidnug fits

Quidnug’s guardian model (QDP-0002) and nonce ledger (QDP-0001) are the exact primitives a custody shop needs, upgraded beyond typical multi-sig:

ProblemQuidnug primitive
”Which keys can authorize a transfer?”GuardianSet for each wallet/account
”Rotate a key every 90 days”AnchorRotation with MaxAcceptedOldNonce
”Invalidate a compromised key immediately”AnchorInvalidation (freeze epoch)
“Emergency recovery with oversight”GuardianRecovery with time-lock veto
”Forensically audit last year’s activity”Ledger snapshot + signed event stream
”Coordinate policy across subsidiaries”Fork-block transaction at shared height
”Detect stale-key signatures”Lazy epoch probe (QDP-0007)

High-level architecture

Quidnug Custody Root
(company-level identity)
│ has guardians:
│ {CEO, CISO, COO, external-auditor}
┌──────────────────────────────┐
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ US Vault │ │ EU Vault │
│ (subsidiary) │ │ (subsidiary) │
└──────┬───────┘ └──────┬───────┘
│ │
│ has approvers: │
│ {signer1, signer2, │
│ signer3, signer4, │
│ signer5} │
▼ ▼
┌───────────────┐ ┌───────────────┐
│ Wallet accounts│ │Wallet accounts│
│ (one quid each)│ │(one quid each)│
└───────────────┘ └───────────────┘
│ │
▼ ▼
On-chain (multi-sig On-chain (multi-sig
contract executes) contract executes)

Each level has its own guardian set with distinct rules:

  • Root: requires executive-level quorum for structural changes.
  • Subsidiary: declares the pool of authorized approvers.
  • Individual wallet: specifies the specific threshold for that wallet (e.g., cold-storage wallet might require 5-of-7 vs. hot-wallet 2-of-3).

Data model

Wallet as a quid

Each custody wallet is a quid. Its guardian set is the set of authorized signers. The wallet’s on-chain (Ethereum/Bitcoin/ etc.) multi-sig contract is configured to accept signatures that match the quorum declared on Quidnug.

wallet-cold-btc-001 (quid)
GuardianSet:
guardians: [signer1(w=1), signer2(w=1), signer3(w=1),
signer4(w=1), signer5(w=1), signer6(w=1), signer7(w=1)]
threshold: 5 # 5-of-7
recoveryDelay: 7 days # long time-lock for cold storage
requireGuardianRotation: true # no primary-key fast path

Approval as title + events

A transfer authorization is a title representing “the authorization to transfer X from wallet Y”. Approvers cosign via events (same pattern as interbank wires).

title: "tx-auth-2026-04-18-abc"
owner: wallet-cold-btc-001
attributes:
targetChain: "bitcoin"
targetAddress: "bc1q..."
amount: "10.5"
currency: "BTC"
proposedAt: <unix>
events on this title:
- wire.cosign {signer: signer1, epoch: 0}
- wire.cosign {signer: signer2, epoch: 0}
- wire.cosign {signer: signer3, epoch: 0}
- wire.cosign {signer: signer4, epoch: 0}
- wire.cosign {signer: signer5, epoch: 0} ← quorum met
- wire.approved (system-emitted)

Once the wire.approved event fires, the subsidiary’s bridge system extracts each signer’s signature and submits to the on-chain multi-sig contract.

Epoch-based audit

Every signer’s signing key has an epoch, an integer that monotonically advances on each rotation. A historical transfer audit looks like:

"Transfer X was approved at block 123456:
- signer1 signed at epoch=2 (rotated 2026-02-15)
- signer2 signed at epoch=3 (rotated 2026-03-20)
- signer3 signed at epoch=1 (rotated 2025-11-05)
- signer4 signed at epoch=0 (never rotated, still original onboarding key!)
- signer5 signed at epoch=2
Quorum weight: 5 of 5. Threshold: 5. APPROVED."

An auditor immediately sees that signer4 is overdue for a rotation. Actionable.

Quarterly rotation workflow

Every 90 days, each signer rotates their key:

1. Generate new keypair in HSM (signer's local ceremony).
2. Submit AnchorRotation:
- fromEpoch: current
- toEpoch: current + 1
- newPublicKey: <hex>
- minNextNonce: 1
- maxAcceptedOldNonce: 100 (grace for in-flight approvals)
3. Nodes across subsidiaries automatically learn of the rotation
via push gossip (QDP-0005). In-flight transfer titles
that the signer had started approving still complete
under their old-epoch key up to the cap.
4. New transfers are signed with the new-epoch key.

If the rotation doesn’t happen within the policy window, a monitoring rule triggers an alert and (optionally) an auto-invalidation of the stale epoch, locking the signer out until they complete the rotation.

Emergency key loss

Scenario: signer3’s HSM catastrophically fails at 2am Sunday. Several transfers are in flight. Recovery:

1. Ops confirms HSM is bricked (standard diagnostic).
2. signer3's personal guardians initiate recovery:
- signer3's manager
- signer3's backup HSM (stored in separate geo)
- the subsidiary's compliance officer
(3-of-5 recovery guardians; see signer3's own GuardianSet)
3. Recovery anchor submitted. Time-lock window begins
(7 days for cold-wallet signer, 1h for hot).
4. During delay: each in-flight transfer can still complete
with signer3's original signatures.
5. If signer3 is actually fine (just on vacation) and this is
a social-engineering attempt, signer3 can veto from a
different trusted device.
6. At delay expiration: commit fires. signer3's epoch advances.
Any future signatures require the new HSM.

No emergency vendor calls. No protocol downtime. Just a cryptographically-auditable flow.

Subsidiary isolation

EU and US subsidiaries are separate quids with their own approver sets. Moving funds between them is an explicit transfer-out-of-one, transfer-in-to-other flow that requires BOTH subsidiaries’ approval quorums.

Compliance value: US compliance officer can’t unilaterally move funds sitting in the EU subsidiary. EU data-privacy rules are enforceable because EU subsidiary’s approvals don’t implicitly grant US access.

Key Quidnug features

  • Guardian sets with requireGuardianRotation, blocks primary-key-only rotations on sensitive quids. Every rotation goes through the time-locked guardian path.
  • AnchorRotation with MaxAcceptedOldNonce, bounded grace window for rotation.
  • AnchorInvalidation, immediate kill-switch for compromised keys.
  • GuardianResignation (QDP-0006), signer departs, formally resigns.
  • Push gossip (QDP-0005), rotations propagate across EU/US nodes within seconds.
  • Lazy epoch probe (QDP-0007), the US subsidiary’s node detecting “hasn’t seen signer-EU-3 sign in 35 days” probes the EU home domain before accepting a signature.
  • K-of-K bootstrap (QDP-0008), opening a new subsidiary in APAC bootstraps from US + EU + two other peers.
  • Fork-block trigger (QDP-0009), when the firm raises the minimum threshold to 6-of-9 globally, fork-block coordinates all subsidiaries.

Value delivered

DimensionBeforeWith Quidnug
Quarterly key rotationManual, ceremony + ticketSigner-initiated anchor; auditable chain
Key-loss recoveryEmergency vendor callGuardian recovery with time-lock
Audit “who signed what and when”Cross-system reconciliationSingle chain query
Cross-subsidiary transferSeparate approval chains + emailCross-subsidiary quorum natively supported
Insider-removalRevoke HSM cert + retrain multi-sigGuardian-set update (on-chain, verifiable)
Compliance reportingQuarterly manual extractQuery the blockchain
Forensic reconstruction of incidentHope you have screenshotsReplay the chain; every approval has signer+epoch

What’s in this folder

Runnable POC

Full end-to-end demo at examples/institutional-custody/:

  • custody_policy.py, pure decision logic: wallet policy, signer approvals, epoch-aware counting, frozen-wallet denial.
  • custody_policy_test.py, 14 pytest cases covering the threshold / impostor / stale-epoch / freeze matrix.
  • demo.py, eight-step end-to-end flow: register 7 signers, install a 5-of-7 policy, propose a transfer, watch the verdict transition pending -> authorized as cosignatures accumulate, render the forensic audit, freeze, and observe denial of a follow-on transfer.
Terminal window
cd examples/institutional-custody
python demo.py

Implementation

Concrete API calls, pseudocode, signing shape.

Implementation: Institutional Custody

Concrete Quidnug setup for a multi-jurisdiction custody firm.

0. Topology

Three Quidnug nodes minimum:

  • node-us.custody.example (US subsidiary)
  • node-eu.custody.example (EU subsidiary)
  • node-root.custody.example (firm-level coordination)

Each runs a Quidnug node with:

ENABLE_NONCE_LEDGER=true
ENABLE_PUSH_GOSSIP=true
ENABLE_LAZY_EPOCH_PROBE=true
ENABLE_KOFK_BOOTSTRAP=true
SEED_NODES=[...]
NODE_AUTH_SECRET=...

1. Hierarchical identity setup

Terminal window
# 1a. Root identity (rarely used; kept cold)
curl -X POST $NODE_ROOT/api/identities -d '{
"quidId":"custody-root",
"name":"Custody Firm Root",
"creator":"custody-root",
"updateNonce":1,
"attributes":{"jurisdictions":["US","EU"]}
}'
# 1b. Root guardian set, 3-of-4 executive quorum
curl -X POST $NODE_ROOT/api/v2/guardian/set-update -d '{
"subjectQuid":"custody-root",
"newSet":{
"guardians":[
{"quid":"ceo-quid","weight":1,"epoch":0},
{"quid":"ciso-quid","weight":1,"epoch":0},
{"quid":"coo-quid","weight":1,"epoch":0},
{"quid":"ext-auditor-quid","weight":1,"epoch":0}
],
"threshold":3,
"recoveryDelay":604800000000000, /* 7 days in ns */
"requireGuardianRotation":true
},
...
}'
# 1c. US subsidiary quid
curl -X POST $NODE_US/api/identities -d '{
"quidId":"custody-us",
"name":"US Custody Subsidiary",
"creator":"custody-root",
"updateNonce":1
}'
# 1d. US subsidiary guardian set
curl -X POST $NODE_US/api/v2/guardian/set-update -d '{
"subjectQuid":"custody-us",
"newSet":{
"guardians":[
{"quid":"us-signer-1","weight":1,"epoch":0},
{"quid":"us-signer-2","weight":1,"epoch":0},
{"quid":"us-signer-3","weight":1,"epoch":0},
{"quid":"us-signer-4","weight":1,"epoch":0},
{"quid":"us-signer-5","weight":1,"epoch":0}
],
"threshold":3,
"recoveryDelay":86400000000000, /* 1 day */
"requireGuardianRotation":false /* subsidiary can have fast-path */
},
...
}'
# Repeat for EU.

2. Wallet setup

Each wallet is its own quid:

Terminal window
curl -X POST $NODE_US/api/identities -d '{
"quidId":"wallet-cold-btc-001",
"name":"US Cold Storage BTC Wallet 001",
"creator":"custody-us",
"updateNonce":1,
"attributes":{
"chain":"bitcoin",
"type":"cold-storage",
"onChainAddress":"bc1q...",
"limit":"100" /* BTC */
}
}'
# Cold wallet: 5-of-7 quorum, 7-day delay, required guardian rotation
curl -X POST $NODE_US/api/v2/guardian/set-update -d '{
"subjectQuid":"wallet-cold-btc-001",
"newSet":{
"guardians":[
{"quid":"us-signer-1","weight":1,"epoch":0},
/* ... 7 signers ... */
],
"threshold":5,
"recoveryDelay":604800000000000,
"requireGuardianRotation":true
},
...
}'
# Hot wallet: 2-of-3 quorum, 1-hour delay
# (configure separately per wallet)

3. Transfer authorization flow

Same as interbank wires, see ../interbank-wire-authorization/implementation.md §3 for the detailed sequence. Key differences:

  • Title includes targetChain, targetAddress, amount.
  • Quorum check runs against the wallet’s specific guardian set.
  • On approval, subsidiary’s bridge extracts signatures and submits to the on-chain multi-sig contract.

4. Quarterly rotation automation

package custody
func (c *Custodian) AutoRotateSigners(ctx context.Context, maxAgeDays int) error {
signers := c.ListSigners()
for _, signer := range signers {
lastRotation := c.GetLastRotationAnchor(signer.Quid)
age := time.Since(time.Unix(lastRotation.Timestamp, 0))
if age.Hours() > float64(maxAgeDays)*24 {
// Overdue, notify the signer and begin rotation.
c.NotifySignerRotationDue(signer)
continue
}
if age.Hours() > float64(maxAgeDays-14)*24 {
// 14-day warning
c.NotifyUpcomingRotation(signer)
}
}
return nil
}
func (c *Custodian) InitiateRotation(ctx context.Context, signerQuid string, newPubKey string) error {
current := c.ledger.CurrentEpoch(signerQuid)
nextNonce := c.ledger.LastAnchorNonce(signerQuid) + 1
rotation := core.NonceAnchor{
Kind: core.AnchorRotation,
SignerQuid: signerQuid,
FromEpoch: current,
ToEpoch: current + 1,
NewPublicKey: newPubKey,
MinNextNonce: 1,
MaxAcceptedOldNonce: 100, /* grace for in-flight approvals */
AnchorNonce: nextNonce,
ValidFrom: time.Now().Unix(),
}
signable, _ := core.GetAnchorSignableData(rotation)
rotation.Signature = signWithCurrentEpochHSM(signerQuid, signable)
return c.submitAnchor(rotation)
}

5. Emergency invalidation

A signer’s key is confirmed compromised. Immediate action:

Terminal window
# Freeze the epoch
curl -X POST $NODE_US/api/anchors -d '{
"kind":"invalidation",
"signerQuid":"us-signer-3",
"epochToInvalidate":2,
"anchorNonce":<next>,
"validFrom":<now>,
"signature":"<signed by a currently-trusted signer or via guardian quorum>"
}'

Now no further transactions at that epoch are admitted anywhere in the network (even cross-subsidiary).

6. Cross-subsidiary transfer

US wallet → EU wallet transfer:
1. US subsidiary creates an "outbound transfer" title with their
5-of-7 quorum.
2. Their on-chain multi-sig executes: funds move from US BTC
address to EU BTC address.
3. EU subsidiary creates an "inbound attestation" title
confirming receipt, cosigned by EU's quorum.
4. Both titles link to each other via a shared correlation ID.
Compliance sees a full chain: US approvers + EU approvers both
on-chain.

7. Lazy epoch probe in action

The US subsidiary has signer-EU-3 in its trust graph (for cross-subsidiary transfer verification). EU-3 hasn’t signed anything the US node has seen in 35 days.

When a new cross-subsidiary transfer arrives with EU-3’s signature:

US node:
1. Check recency of EU-3: > 7-day window → stale.
2. Quarantine the transaction.
3. Probe EU's domain: GET /api/v2/domain-fingerprints/eu.custody/latest
4. EU node responds with its latest fingerprint; EU-3's epoch
is 4 (they rotated 3 times we didn't see).
5. US ledger updates EU-3's epoch.
6. Re-validate the transaction: signed at epoch 4? OK, accept.
signed at stale epoch 2? Reject.

Catches the scenario where an attacker has EU-3’s old (rotated- out) key and tries to use it in the US.

8. Subsidiary opening (bootstrap)

Opening an APAC subsidiary:

Terminal window
# 8a. APAC node is fresh. Bootstrap trust list seeded by firm ops:
# (3 known-good peers: US, EU, external auditor)
apacNode.SeedBootstrapTrustList([]core.BootstrapTrustEntry{
{Quid:"custody-us",PublicKey:"<hex>"},
{Quid:"custody-eu",PublicKey:"<hex>"},
{Quid:"ext-auditor-quid",PublicKey:"<hex>"},
}, 3)
sess, _ := apacNode.BootstrapFromPeers(ctx, "custody.firm.global",
core.DefaultBootstrapConfig())
if sess.State == core.BootstrapQuorumMet {
apacNode.ApplyBootstrapSnapshot(64)
}

9. Policy change: raise threshold globally

Firm decides all wallets now need 6-of-9 instead of 5-of-7. Fork-block coordination:

Terminal window
curl -X POST $NODE_ROOT/api/v2/fork-block -d '{
"trustDomain":"custody.firm.global",
"feature":"require_tx_tree_root", /* placeholder for the actual policy update */
"forkHeight":<future>,
"forkNonce":1,
"signatures":[ /* executive quorum */ ]
}'

At the fork height, every subsidiary’s nodes apply the new policy simultaneously.

10. Audit report generation

func (c *Custodian) GenerateQuarterlyAudit(ctx context.Context, q Quarter) AuditReport {
report := AuditReport{}
// 1. For each wallet, list all transfers that completed in
// the quarter.
for _, wallet := range c.ListWallets() {
transfers := c.ListApprovedTransfers(wallet.Quid, q.Start, q.End)
for _, t := range transfers {
entry := AuditEntry{
WalletID: wallet.Quid,
TransferID: t.TitleID,
Amount: t.Amount,
Signers: []SignerInfo{},
}
for _, sig := range t.Signatures {
// Look up the signer's epoch at the time of signing
epoch := c.ledger.EpochAt(sig.SignerQuid, t.BlockHeight)
entry.Signers = append(entry.Signers, SignerInfo{
Quid: sig.SignerQuid,
Epoch: epoch,
LastRotated: c.LastRotationTime(sig.SignerQuid, epoch),
})
}
report.Entries = append(report.Entries, entry)
}
}
// 2. List all guardian-set changes in the quarter.
report.SetChanges = c.GuardianSetChangesInRange(q.Start, q.End)
// 3. List all rotations and invalidations.
report.Rotations = c.RotationsInRange(q.Start, q.End)
report.Invalidations = c.InvalidationsInRange(q.Start, q.End)
return report
}

11. Testing

func TestCustody_ColdWalletRequiresFullQuorum(t *testing.T) {
// 5-of-7 cold wallet, only 4 signatures → not approved
}
func TestCustody_EpochRotationDoesNotAffectInFlight(t *testing.T) {
// Signer starts approving a transfer with epoch 0
// Signer rotates to epoch 1
// Transfer completes with remaining signers' epoch-1 sigs
// Original epoch-0 signature still valid (within MaxAcceptedOldNonce)
}
func TestCustody_CrossSubsidiaryStaleKeyDetected(t *testing.T) {
// US node hasn't seen EU-3 in 35d
// EU-3 has rotated 3 times
// Attack with old-epoch EU-3 sig detected via lazy probe
}

Where to go next

Threat model

Adversaries, assumed capabilities, mitigations.

Threat Model: Institutional Custody

Assets

  1. Client crypto holdings, the primary asset. Theft is the catastrophic outcome.
  2. Signer keys, HSM-protected; compromise of enough keys approves theft.
  3. Guardian keys, recovery authority; compromise enables malicious rotation to attacker-controlled keys.
  4. Root quid key, structural authority. Catastrophic if compromised (can rewrite guardian sets).

Attackers

AttackerCapabilityGoal
ExternalNo access to any firm infrastructureSteal holdings
Insider: signerHas one signing HSMParticipate in theft
Insider: sysadminCan reboot nodes, modify config, not keysSubtle sabotage
Insider: executiveGuardian quorum memberCollusion
State adversaryNetwork observer, legal compulsionSurveillance / seizure
Supply-chainCompromised dependency, HSM firmwarePersistent backdoor
Social engineerAccess to signers via email / phoneTrick into signing

Threats

T1. Theft via compromised signer quorum

Attack. Attacker compromises 5 of 7 cold-wallet signers’ HSMs and triggers a transfer to their own address.

Mitigations.

  • Cold-wallet quorum is high (5-of-7 minimum). Compromising 5 independent HSMs is a major operation.
  • Signers spread geographically and across HSM vendors, correlated-HSM-compromise is much harder than a single vendor bug.
  • requireGuardianRotation=true on cold wallets means any signer-set change goes through time-locked guardian recovery, giving compliance / ops a window to intervene.

Residual risk. Determined state-level adversary with multiple independent compromises. Mitigated by insurance + monitoring + air-gapped cold signers.

T2. Insider collusion

Attack. Three signers + compliance officer collude to move funds to an attacker-controlled address.

Mitigations.

  • Quorum math should be set so any single insider group can’t meet threshold (N-1 if possible). Cold wallet with 5-of-7 means 3 colluders can’t succeed.
  • Periodic rotation (every 90 days) limits the window of stable collusion.
  • Executive-level oversight: guardian-set updates require root quid’s guardians (CEO, CISO, COO, auditor), a signer-level collusion can’t amend the quorum structure.

Residual risk. Sufficient collusion (5+ people) defeats any quorum. Mitigated by culture, rotation, compensation design.

T3. Guardian-quorum takeover

Attack. Attacker compromises a signer’s personal guardians (spouse, manager, backup HSM) and initiates a recovery to an attacker-controlled key.

Mitigations.

  • recoveryDelay of 7 days for cold-wallet signers. During this window, the legit signer (if they’re fine) can veto.
  • Veto mechanism: any of the personal guardians can veto a pending recovery if the signer has an out-of-band way to contact them.
  • EnableLazyEpochProbe (QDP-0007) means unexpected rotations fire visible cross-subsidiary events that compliance sees.

Residual risk. Attacker with access to both the signer’s HSM AND sufficient personal guardians can complete a recovery. Mitigated by physical security of backup HSMs, guardian rotation, and periodic re-attestation.

T4. Root quid compromise

Attack. CEO’s phone is stolen + phished. Attacker initiates a guardian-set update modifying the root’s structure.

Mitigations.

  • Root guardians are {CEO, CISO, COO, external auditor}, 2 executives + external auditor required for quorum.
  • External auditor is organizationally independent, phishing them separately is unlikely.
  • requireGuardianRotation=true on root means no fast-path.
  • 7-day delay at root level → lots of time for anomaly detection.

Residual risk. Low; all top-level keys would have to be simultaneously compromised.

T5. Stale-key attack across subsidiaries

Attack. Attacker gets hold of a signer’s OLD key (pre- rotation) and tries to use it in a subsidiary that hasn’t observed the rotation.

Mitigations.

  • Push gossip (QDP-0005) propagates rotations across subsidiaries in seconds to minutes.
  • Lazy epoch probe (QDP-0007) catches the case where push missed a subsidiary: the receiving node probes the signer’s home domain before accepting a stale-looking signature.
  • MaxAcceptedOldNonce cap (default 100) limits the grace window.

Residual risk. Window between rotation and propagation is short and monitorable.

T6. Replay of a signed approval

Attack. Intercepted approval for transfer A replayed as transfer B.

Mitigations.

  • Signatures bind to the specific title’s canonical content. Different content = different signable bytes = signature mismatch.
  • Anchor-nonce monotonicity: same nonce can’t appear twice.

Residual risk. None.

T7. On-chain multi-sig contract bug

Attack. The Bitcoin / Ethereum multi-sig contract that ultimately executes the transfer has a vulnerability.

Mitigations.

  • This is the on-chain side, not Quidnug’s responsibility. Quidnug authorizes; the on-chain contract enforces.
  • Multi-sig contracts are extensively audited and battle- tested (Gnosis Safe, etc.).

Residual risk. Outside this use case’s scope.

T8. Signer ransomware

Attack. Attacker encrypts a signer’s HSM interface and demands ransom to unlock.

Mitigations.

  • Signers have backup HSMs in separate locations.
  • Guardian recovery lets the firm rotate the ransomware’d signer to a fresh HSM in under 7 days (or minutes for hot wallets).
  • Temporary quorum reduction is possible via guardian- set update (4-of-6 until the 7th signer is replaced).

Residual risk. Minor operational disruption; no fund loss.

T9. Fork-block abuse

Attack. Executive quorum pushes a fork-block that lowers quorum thresholds, enabling a later insider attack.

Mitigations.

  • Fork-block requires 2/3 of domain validators, this is the consortium governance layer, not an internal-only decision.
  • MinForkNoticeBlocks = 1440 (~24h) notice.
  • External auditor in the executive quorum provides independent oversight.

Residual risk. Majority-executive collusion. Mitigated by governance, insurance, and audit.

T10. Regulatory compulsion

Attack. State actor subpoenas the firm’s root signing keys.

Mitigations.

  • Keys are HSM-protected; the firm cannot “hand over” keys directly, they can be used but not extracted.
  • Transfers still require quorum; a compelled executive signature alone doesn’t meet threshold.
  • Multi-jurisdictional signers: US subsidiary’s signers aren’t subject to EU court orders and vice versa.

Residual risk. If enough jurisdictions’ signers are compelled simultaneously, compulsion can force transfers. This is the deliberate “compliance with subpoenas” path; no protocol avoids it.

Not defended against

  1. Off-chain custody (cash, paper certificates). Quidnug is for cryptographic assets with signed transactions.
  2. User-level social engineering. If an attacker convinces a signer to actually sign a malicious transfer, the system works as designed.
  3. Multi-subsidiary collusion. EU + US executives both corrupt = bigger than protocol-level concern.
  4. Privacy of holdings. On-chain balances are visible; this is a blockchain property, not something Quidnug changes.

Monitoring

Critical Prometheus metrics + alerts:

MetricThresholdAction
quidnug_guardian_resignations_rejected_total> 0 in 24hInvestigate
quidnug_guardian_set_weakened_total{subject=wallet}anyPager
Rotation age > policy (custom)> 100 daysAlert signer
Un-rotated epoch age (custom)> 365 daysPager + freeze
quidnug_probe_failure_total{reason="all_failed"}> 5/minCheck subsidiary link
quidnug_nonce_replay_rejections_total{enforced=true}anyPager (attack attempt)

Incident response playbook

  1. Signer HSM compromise suspected.

    • Invalidate epoch immediately: POST /api/anchors {kind:"invalidation"}
    • Initiate guardian recovery for a replacement HSM.
    • Audit all transactions from that signer in the last 30 days.
  2. Root guardian concern (CEO phone stolen).

    • Immediately invalidate CEO’s epoch.
    • All other root guardians (CISO, COO, auditor) are alerted.
    • Pending root-guardian-set updates blocked; they require CEO’s key, which is now frozen.
    • Rotate CEO’s key through the root guardian quorum.
  3. Unexpected guardian-set update detected.

    • Operator halts nodes.
    • Review the update’s authorizing signatures.
    • If malicious: file emergency halt with consortium; no further transactions signed while investigation runs.

References