Skip to content

Bureau — Blue Team (defensive)

Press-Pipe

The chain of custody from a confidential source's drop through editorial review and downstream citation has historically been informal. Press-Pipe signs every link in that chain so each hop is independently verifiable.

Posture: 🔵 Blue Team (defensive)   ·   Status: alpha

What it does

When a source provides sensitive documents to a newsroom, the chain from intake to publication is typically a mix of PGP, encrypted messaging, and informal notes. Three failure modes are common: documents are altered between source and editor; a downstream outlet "cites" a leaked dossier whose bytes do not actually match the source; and criminal evidence does not reach regulators because the routing decision is informal and unauditable.

Press-Pipe addresses all three by signing every hop. The source drop is signed at the Tor intake (only the SHA-256 digest of the document, never the cleartext). The editor reproduces the digest and signs an editor receipt asserting "I received the document with this exact hash." The newsroom publishes a dossier; downstream outlets that cite it sign their citations as leaves on the same tree. If document bytes are altered, the digests no longer match and a drop-tampered proof is emitted. If a citation does not reproduce, a citation-fabricated proof is emitted. When evidence is flagged for regulator routing, the Bounty composition routes it to SEC, FTC, or ICC and signs the routing decision.

Who would use it

  • An investigative newsroom (ProPublica, ICIJ, Bellingcat) standardizing source-chain integrity.
  • A whistleblower-facing intake organization (SecureDrop operators, GlobaLeaks deployers).
  • A downstream aggregator (404 Media, The Verge) that cites primary newsroom dossiers.
  • A regulator (SEC, FTC, ICC) accepting cryptographically-routed criminal evidence.
  • A nonprofit fact-checker validating that "leaked" documents actually match source-side commitments.

What you'll need

  • The Pluck CLI (npm install -g @sizls/pluck-cli).
  • For source intake: a Tor hidden service running the Whistle composition, plus an Ed25519 signing key for the intake operator.
  • For editorial: the editor's signing key and reproduce-digest tooling. The Pluck CLI ships a Node-based reproducer.
  • For publication: a signed dossier and a public Rekor notarization.
  • For regulator routing: a Bounty configuration mapping evidence type to SEC, FTC, or ICC endpoints.

Step-by-step

The alpha runs the full constraint chain on synthetic drops, receipts, and citations – there is no live Tor intake daemon yet. Production capture and verify ship in a follow-up. To exercise the system today:

Shell
pluck bureau press-pipe demo

Expected output: the system ingests two source drops, two editor receipts, and two downstream citations (one legitimate chain plus one tampered drop and one fabricated citation), and emits two signed proofs (drop-tampered and citation-fabricated). Each proof carries the digests in question and an Ed25519 signature you can independently verify against the Rekor entry.

What to do with the output: in production the WHISTLE intake daemon runs continuously on a Tor hidden service, the editor runs the reproduce-digest pass on every received document, and downstream outlets sign their citations into the same tree. Verifiers fetch Rekor entries and re-derive the chain – no newsroom or platform cooperation required.

Run it yourself

Drop this into a Node 18+ project (npm install @sizls/pluck-bureau-press-pipe @sizls/pluck-bureau-core tsx):

TypeScript
// index.ts
import { createHash } from "node:crypto";
import {
  createPressPipeSystem,
  fingerprintPrivateKey,
  signCanonicalBody,
  type Citation,
  type EditorReceipt,
  type SourceDrop,
} from "@sizls/pluck-bureau-press-pipe";
import { generateOperatorKey } from "@sizls/pluck-bureau-core";

async function main() {
  const operator = generateOperatorKey();
  const whistle = generateOperatorKey();
  const editor = generateOperatorKey();
  const outlet = generateOperatorKey();
  const whistleFp = fingerprintPrivateKey(whistle.privateKeyPem);
  const editorFp = fingerprintPrivateKey(editor.privateKeyPem);
  const outletFp = fingerprintPrivateKey(outlet.privateKeyPem);

  const torPipe = digest("pipe:tor-onion-redacted");
  const proPublica = digest("outlet:propublica");
  const fourOhFour = digest("outlet:404media");
  const dropDigest = digest("evidence:dump-A");
  const wrongDigest = digest("evidence:dump-A:tampered");
  const dossierHash = digest("dossier:propublica:legit");

  const press = createPressPipeSystem({
    signingKey: operator.privateKeyPem,
    disablePausePoll: true,
    disableLogging: true,
  });

  try {
    // 1) Source drop signed by WHISTLE.
    const drop = buildDrop(torPipe, dropDigest, undefined, "2026-04-26T00:01:00.000Z", whistle.privateKeyPem, whistleFp);
    press.observeDrop(drop);

    // 2) Editor reproduces a DIFFERENT digest – fires drop-tampered.
    press.registerReceipt(buildReceipt(drop.dropId, wrongDigest, proPublica, dossierHash, "2026-04-26T00:06:00.000Z", editor.privateKeyPem, editorFp));

    // 3) Citation in reproduction mode whose cassetteRef doesn't match the dossierHash – fires citation-fabricated.
    press.observeCitation(buildCitation("reproduction", dossierHash, digest("dossier:404media:fabricated"), fourOhFour, "2026-04-26T00:31:00.000Z", outlet.privateKeyPem, outletFp));

    for (let i = 0; i < 60; i++) await new Promise((r) => setImmediate(r));

    const proofs = press.facts.proofs();
    console.log(`press-pipe proofs = ${proofs.length}`);
    for (const p of proofs) console.log(`kind=${p.kind} proofId=${p.proofId.slice(0, 16)}`);
  } finally {
    await press.shutdown();
  }
}

function digest(s: string): string { return createHash("sha256").update(s).digest("hex"); }

function buildDrop(pipeHash: string, dropDigest: string, prevDigest: string | undefined, receivedAt: string, whistleKey: string, whistleFingerprint: string): SourceDrop {
  const skeleton = { schemaVersion: 1 as const, pipeHash, dropDigest, ...(prevDigest !== undefined ? { prevDigest } : {}), receivedAt, whistleFingerprint };
  const dropId = createHash("sha256").update(JSON.stringify(skeleton)).digest("hex");
  const signed = signCanonicalBody({ ...skeleton, dropId }, whistleKey);
  return { ...skeleton, dropId, signature: signed.signature };
}

function buildReceipt(dropId: string, dropDigest: string, outletHash: string, cassetteRef: string, signedAt: string, editorKey: string, editorFingerprint: string): EditorReceipt {
  const chainDigest = createHash("sha256").update(`${dropDigest}|${cassetteRef}|${signedAt}`).digest("hex");
  const skeleton = { schemaVersion: 1 as const, dropId, dropDigest, outletHash, chainDigest, signedAt, editorFingerprint };
  const receiptId = createHash("sha256").update(JSON.stringify(skeleton)).digest("hex");
  const signed = signCanonicalBody({ ...skeleton, receiptId }, editorKey);
  return { ...skeleton, receiptId, signature: signed.signature };
}

function buildCitation(mode: Citation["mode"], dossierHash: string, cassetteRef: string, citingOutletHash: string, citedAt: string, outletKey: string, citingFingerprint: string): Citation {
  const skeleton = { schemaVersion: 1 as const, mode, dossierHash, cassetteRef, citingOutletHash, citedAt, citingFingerprint };
  const citationId = createHash("sha256").update(JSON.stringify(skeleton)).digest("hex");
  const signed = signCanonicalBody({ ...skeleton, citationId }, outletKey);
  return { ...skeleton, citationId, signature: signed.signature };
}

main().catch((err) => { console.error(err); process.exit(1); });

Run with tsx index.ts. Expected output:

press-pipe proofs = 2
kind=drop-tampered proofId=…
kind=citation-fabricated proofId=…

Open in StackBlitz – runs in your browser, no install required.

What you get

A signed PressPipe.Proof with one of three kind values:

  • drop-tampered – the source document at the editor's end does not reproduce the digest signed at intake.
  • citation-fabricated – a downstream outlet asserts they reproduced the dossier, but their digest doesn't match.
  • auto-file-routed – Bureau-signed routing record showing criminal evidence moved to a regulator with the timestamp and destination signed.

The Bureau never carries cleartext source material. Even if a notarized Press-Pipe proof is published worldwide, it cannot deanonymize the source.

What it can't do

  • Press-Pipe does not protect the source's identity outside the Tor channel. Source security still depends on operational discipline (no metadata leakage, no in-band identity).
  • A compromised editor key can sign false receipts. The proof catches downstream chain breaks but cannot detect a corrupted editor unless paired with a multi-party editorial signature.
  • Press-Pipe does not adjudicate truth or significance – only integrity. A falsifiable chain with verified digests still has to be reported responsibly.
  • The auto-file routing depends on a working regulator endpoint. The system signs the routing decision; the regulator's response is out of scope.

A real-world example

An employee at a financial regulator obtains internal memos relating to an investigation. They submit the memos via the newsroom's Whistle Tor intake. The intake daemon emits a SourceDrop with a digest the employee can recompute locally; they retain the receipt. The newsroom's editor reproduces the digest and signs the receipt. The newsroom publishes a 5,000-word feature with a published dossier root. A second outlet picks up the story, cites the dossier, and signs a Citation. The Bounty composition flags the memos as SEC-routable and emits a signed auto-file-routed proof. Subsequent disputes about whether the memos exist or were materially altered can be resolved by recomputing the digests against the published Rekor entries.


For developers

Predicate URIs

URIWhat it attests
https://pluck.run/PressPipe.SourceDrop/v1Anonymous source submission digest plus per-pipe chain link.
https://pluck.run/PressPipe.EditorReceipt/v1Editor's reproduction-of-digest commitment plus downstream chain link.
https://pluck.run/PressPipe.Citation/v1Downstream outlet's reproduction or commentary citation.
https://pluck.run/PressPipe.Proof/v1Published proof with kind (drop-tampered, citation-fabricated, auto-file-routed).

Programs composed

  • Whistle – anonymous source intake (Tor, post-quantum hybrid signing).
  • Custody – drop → editor → publication chain-of-custody.
  • Bounty – auto-file routing to SEC, FTC, ICC for criminal evidence.
  • Nuclei – newsroom-published verification probe-packs (third-party reproducibility).

Threat model + adversary

Adversaries are: a hostile party in the source-to-editor channel, a corrupted editor, a downstream outlet that fabricates citations to capture clout, and a regulator that wants the criminal evidence to disappear. Press-Pipe closes the byte-integrity holes; operational source security and regulator follow-through remain organizational. See Threat Model.

Verify a published cassette

Shell
pluck bureau verify <bundle-dir>
cosign verify-blob --key <pubkey.pem> --signature <sig> --type https://pluck.run/PressPipe.Proof/v1 <body.json>

Every published proof is a DSSE envelope notarized to Rekor. Independent verifiers fetch the Rekor entry, verify the Ed25519 signature against the operator's published signing-key fingerprint, and re-derive the chain digests against the source drops. No newsroom or platform participation required.

See also

Edit this page on GitHub
Previous
Power-Ledger

Ready to build?

Install Pluck and follow the Quick Start guide to wire MCP-first data pipelines into your agents and fleets in minutes.

Get started →