did-btcr2-js

ADR 027: Aggregation Protocol Security Hardening and Threat Model

Status: Accepted

Date: 2026-04-14

Commit: 86e2f2b

Context

The initial aggregation subsystem (ADR 020) landed as a working multi-party protocol: cohort formation, update collection, aggregation, validation, MuSig2 signing. Getting it to pass happy-path scenarios came first.

The next step was identifying and mitigating the adversarial-scenario classes a real deployment would face: malicious participants, confused service operators, replay attacks, resource-exhaustion by unbounded message sizes, stale cohorts hanging open forever, etc. This ADR captures the named threat classes the hardening commit addressed and the mitigations chosen.

Threat classes addressed

The regression-test suite at packages/method/tests/aggregation-security.spec.ts pins mitigations for each of the following:

T1: Cohort-membership manipulation

Mitigation: Service state tracks accepted participants; re-opt-ins are idempotent: the cohort key for that DID remains the originally accepted one.

T2: Message-content abuse

Mitigation: maxUpdateSizeBytes enforced in AggregationService.#handleSubmitUpdate before any expensive processing. Oversized updates are dropped with a diagnostic.

T3: Wire-protocol version skew

Mitigation: AGGREGATION_WIRE_VERSION = 1 is checked on every message at ingestion. Mismatched messages are rejected, not silently processed as a possibly-incompatible shape.

T4: Cohort-lifecycle failure modes

Mitigation: Cohort TTL causes timed cohorts to transition to Failed and emit cohort-failed on the runner. A single validation-ack with approved: false transitions the phase to Failed on both sides.

T5: MuSig2 signing-session hygiene

Mitigation:

Decision

Adopt the mitigations above. Encode each as a regression test in aggregation-security.spec.ts. The test suite is the durable contract: if any mitigation regresses, a named test fails with the associated threat label.

Runner-side behavior: on every rejection, emit a diagnostic event (error, cohort-failed) with enough context to debug.

Consequences

Positive

Negative

Explicitly not covered here

References