- Docs
- Bureau — Blue Team (defensive)
- Gossip
Bureau — Blue Team (defensive)
Gossip
Pluck Bureau as currently deployed treats Pluck Inc. as a singular trust anchor, which is a single point of failure. Gossip turns each operator into a peer in a cross-attesting mesh; observations require k-of-n peer agreement before being treated as mesh-attested.
Posture: 🔵 Blue Team (defensive) · Status: alpha (moonshot)
What it does
Currently, every Bureau program – Tripwire, Dragnet, Stingray, Nuclei – produces proofs that ultimately resolve to a single operator's signature. Compromise of, capture of, or legal compulsion against that operator weakens the proofs. For a system designed to attest information that adversaries are motivated to dispute, this is a structural weakness.
Gossip turns each Bureau operator into a peer in a cross-attesting mesh. When any Bureau program emits an observation, peers in the mesh independently co-sign it (or decline to). An observation that reaches k-of-n quorum – k peers agreeing out of n polled, default 3-of-5 – is published as a MeshAttestedRecord. Verifiers do not have to trust any single operator; they verify that k distinct operators, each with their own identity-attesting signers, signed the same digest. No central node controls the network.
Who would use it
- A Bureau operator running Stingray or Dragnet who wants their findings counter-attested before they hit the news cycle.
- A press / NGO consortium (ProPublica, Bellingcat, EFF, Verified Voting, Brennan Center) coordinating election-integrity coverage where each org runs its own Bureau node and co-signs the others' findings.
- A whistleblower platform that needs cryptographic provenance for tips even if the original receiver gets gagged or seized.
- A federated red-team network where each lab co-signs the others' vulnerability disclosures so a single takedown can't bury a finding.
What you'll need
- The Pluck CLI installed (
npm i -g @sizls/pluck-cli). - An operator key per peer. The web-of-trust signers (org-affiliation attestations) are external – Gossip checks SPKI fingerprints, it doesn't establish trust on its own.
- For real deployment: at least n=5 peers willing to mutually peer (more is better). The hardest part is social, not technical.
Step-by-step
pluck bureau gossip demo
The demo wires up five peers – three sock-puppets sharing the same four web-of-trust signers, and two honest peers with distinct singletons. Three observations land. Four co-signatures arrive: three agree on observation #1 (reaching 3-of-5 quorum and emitting a MeshAttestedRecord), and a fourth disagree from a peer that already signed agree (firing co-sign-conflict). The Sybil detector fires on the three-peer cluster.
gossip/demo: ingesting 5 operator peers (3 sybil + 2 honest) + 3 peer observations + 4 co-signatures (3 agree on observation1 -> mesh-attested, 1 conflicting verdict by the same peer) -> 2 GossipProofs + 1 MeshAttestedRecord.
[Bureau/GOSSIP] proof=ddf77340… kind=sybil-detected
[Bureau/GOSSIP] proof=7bc7dfcf… kind=co-sign-conflict
gossip/demo: meshAttested recordId=10cce053… cosigs=3
Production CLI (peer add, peer list, cosign, verify, replay, daemon) lands in a follow-up.
Run it yourself
Drop this into a Node 18+ project (npm install @sizls/pluck-bureau-gossip @sizls/pluck-bureau-core tsx):
// index.ts
import { createHash } from "node:crypto";
import {
createGossipSystem,
fingerprintPrivateKey,
signCanonicalBody,
} from "@sizls/pluck-bureau-gossip";
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 peer = generateOperatorKey();
const peerFp = fingerprintPrivateKey(peer.privateKeyPem);
const observationDigest = sha256("obs:dragnet:claim-A:01");
const system = createGossipSystem({
signingKey: op.privateKeyPem,
quorum: { required: 3, outOf: 5 },
disablePausePoll: true,
disableLogging: true,
});
// Same peer co-signs the same observation with both `agree` and `disagree` -> co-sign-conflict.
for (const verdict of ["agree", "disagree"] as const) {
const body = {
schemaVersion: 1 as const, observationDigest,
cosignerFingerprint: peerFp, verdict,
observedAt: `2026-04-22T10:00:0${verdict === "agree" ? 0 : 3}.000Z`,
};
const cosigId = sha256(JSON.stringify(body));
const { signature } = signCanonicalBody({ ...body, cosigId }, peer.privateKeyPem);
system.receiveCoSignature({ ...body, cosigId, signature });
}
try {
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=co-sign-conflict id=…
▶ Open in StackBlitz – runs in your browser, no install required.
What you get
A MeshAttestedRecord is an Ed25519-signed envelope, Rekor-anchored, containing the original observation digest plus k qualifying peer co-signatures. Anyone can verify it without trusting any single peer.
Three classes of red-team proof when the mesh's honesty protocol breaks:
sybil-detected– three or more peers share ≥80% of their web-of-trust signer set; that looks like one party running sock-puppets. False-positive resistance: peers that disclose they're in the same organization (matchingorgKey, typically tied to an Oath commitment) are treated as one declared entity.co-sign-conflict– the same peer signed two contradicting verdicts on the same observation. A peer cannot be in two truth-states at once.stake-slashed– a peer's stake or reputation has been slashed below threshold by accumulated false-co-signatures.
What it can't do
- A coordinated minority that controls k of n peers can manufacture a false MeshAttestedRecord. Threshold tuning is the operator's responsibility – high-stakes attestations should require larger k.
- A competent adversary running N sock-puppet operators with N independent webs-of-trust is structurally invisible to the Sybil detector. The defense is reputation / stake slashing over a long time horizon.
- Stake economy is stubbed – escrow, on-chain bonding, slash-to-burn are all signed-shape-only in the alpha. Stake / reputation values are operator-supplied numbers; the Bureau does not check them against any external ledger.
- Real Sigstore Rekor
notarizeplumbing is stubbed. - Per-program threshold tuning library deferred – alpha defaults are 3-of-5 quorum and 80% Sybil-overlap.
A real-world example
It's October 2026. Verified Voting, Halderman's lab, the Brennan Center, ProPublica, and EFF are running Pluck Bureau nodes covering the midterm election. On election night, Halderman's Stingray detects an IMSI-catcher equivocation outside a Cook County precinct. His node emits the observation. Within seconds, Verified Voting and the Brennan Center independently re-run the constraint logic on the raw RF data and co-sign agree. EFF co-signs agree. ProPublica co-signs agree. 4-of-5 quorum: a MeshAttestedRecord publishes. By 9pm, ProPublica's reporter has a story whose cryptographic backing does not depend on Halderman's reputation alone. By 11pm, when a state attorney's office disputes the finding and demands Halderman's logs, the dispute is academic – four other independent peers signed the same digest with separately-rooted keys.
For developers
Predicate URIs
| URI | What it attests |
|---|---|
https://pluck.run/Gossip.Peer/v1 | Peer P registered with stake S and web-of-trust signers, at time T. |
https://pluck.run/Gossip.Observation/v1 | Peer P, running program X, signed an observation about subject S with verdict V. |
https://pluck.run/Gossip.CoSign/v1 | Peer P co-signed observation D with verdict V at time T. |
https://pluck.run/Gossip.MeshAttested/v1 | Observation O reached k-of-n quorum at threshold {k, n}. |
https://pluck.run/Gossip.Proof/v1 | Class: sybil-detected | co-sign-conflict | stake-slashed. |
The signed body never carries raw observation bodies – only digests pass through. SPKI fingerprints are deliberately public; the mesh's whole reason to exist is public operator identity.
Programs composed
- Every other Bureau program feeds observations to Gossip – Dragnet, Tripwire, Nuclei, Stingray, AVAP, Icarus, Mole.
- Oath –
orgKeyfield ties a peer to an organization commitment so org-internal peers don't fire Sybil. - Pluck core's DSSE in-toto envelopes + Sigstore Rekor client.
- Directive's facts/constraints/resolvers.
Threat model + adversary
The attacker is a nation-state or large vendor that wants a specific finding silenced. Their levers: subpoena one operator (defeated by k-of-n), compromise one operator's key (defeated), run sock-puppet peers (caught by Sybil unless their wallets are independently rooted, in which case slashing-over-time is the defense). The mesh does not survive a coordinated capture of k peers – it raises the cost.
What's stubbed (alpha – moonshot)
- Real Sigstore Rekor
notarizeplumbing deferred. - Stake economy integration deferred (escrow, on-chain bonding, slash-to-burn).
- Per-program threshold tuning library deferred.
Verify a published cassette
pluck bureau verify <bundle-dir>
cosign verify-blob --key <pubkey.pem> --signature <sig> \
--type https://pluck.run/Gossip.MeshAttested/v1 <body.json>
See also
- Bureau Foundations
- Threat Model
- Verify a dossier
- Oath –
orgKeycommitment registry - Stingray, Dragnet, Nuclei – observation sources