From c994a785a42013890d5f5f9105ea29302a4a17cc Mon Sep 17 00:00:00 2001 From: CLU Date: Thu, 29 Oct 2026 16:24:13 -0500 Subject: [PATCH] feat: render the public site from the database The site is now a view over bigtech.db, not a hand-maintained set of pages. - packages/core/db/render.mjs emits report/.html and method.html into web/public, so Vite copies them into the deployable bundle. Re-running db:build regenerates them from whatever the database currently says. - The report page leads with the score, then the dimension table with the weakest rung highlighted, then findings, then the evidence table with its tiers, then what was not tested, then how to clone and re-run the audit. - The method page publishes the eight weights, the evidence tiers, both caps (reproducible builds and the closed-source ladder), the D1-D4 dynamic test, and a plain section on what the method cannot do. Deployable bundle is 372K: the game, the method, the oath, the catalog and the report. No server-side code, so it can sit on a Caddy static root and be nobody else's problem to host. Rendered 1 report page + method.html. All instrument checks still pass. --- package.json | 9 +- packages/core/db/render.mjs | 252 ++++++++++++++++++ packages/core/src/data/generated/catalog.json | 32 +-- packages/core/src/data/generated/catalog.ts | 32 +-- packages/web/public/catalog.json | 32 +-- packages/web/public/method.html | 154 +++++++++++ packages/web/public/oath.json | 4 +- .../web/public/report/signal-desktop.html | 189 +++++++++++++ 8 files changed, 650 insertions(+), 54 deletions(-) create mode 100644 packages/core/db/render.mjs create mode 100644 packages/web/public/method.html create mode 100644 packages/web/public/report/signal-desktop.html diff --git a/package.json b/package.json index d4053ff..98adbd7 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "bigtech-sucks", "version": "0.1.0", "private": true, - "description": "Draw the Line — a planning site disguised as a retro frontier game", + "description": "Draw the Line \u2014 a planning site disguised as a retro frontier game", "workspaces": [ "packages/*" ], @@ -13,9 +13,10 @@ "build:server": "npm run build -w @bigtech-sucks/server", "preview": "npm run preview -w @bigtech-sucks/web", "test": "npm run test -w @bigtech-sucks/core", - "db:build": "node packages/core/db/build.mjs", + "db:build": "node packages/core/db/build.mjs && node packages/core/db/render.mjs", "db:verify": "node packages/core/db/build.mjs verify", - "db:ingest": "node packages/core/db/ingest/run.mjs" + "db:ingest": "node packages/core/db/ingest/run.mjs", + "db:render": "node packages/core/db/render.mjs" }, "license": "UNLICENSED" -} \ No newline at end of file +} diff --git a/packages/core/db/render.mjs b/packages/core/db/render.mjs new file mode 100644 index 0000000..7fd99ce --- /dev/null +++ b/packages/core/db/render.mjs @@ -0,0 +1,252 @@ +#!/usr/bin/env node +/** + * Render the public site from the living database. + * + * Nothing here is hand-written HTML. Every number on these pages comes out of + * catalog.json, which comes out of bigtech.db, which fails its build if a score + * does not recompute from its evidence. That chain is the product. + * + * Emits: + * packages/web/public/report/.html + * packages/web/public/method.html + */ +import { readFileSync, writeFileSync, mkdirSync } from 'node:fs'; +import { join, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const HERE = dirname(fileURLToPath(import.meta.url)); +const CORE = join(HERE, '..'); +const PUB = join(CORE, '..', 'web', 'public'); +const cat = JSON.parse(readFileSync(join(CORE, 'src', 'data', 'generated', 'catalog.json'), 'utf8')); + +const esc = (s) => String(s ?? '').replace(/[&<>"]/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c])); + +const CSS = ` +:root{--ink:#0d0f0e;--bone:#e8e2d4;--dim:#8a8272;--amber:#d9a441;--good:#7fae7a;--bad:#c9563f;--rule:#2a2d2a} +*{box-sizing:border-box} +body{margin:0;padding:3rem 1.25rem 7rem;background:var(--ink);color:var(--bone); +font-family:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;font-size:15px;line-height:1.7; +-webkit-font-smoothing:antialiased} +.wrap{max-width:58rem;margin:0 auto} +nav{font-size:.72rem;letter-spacing:.18em;text-transform:uppercase;color:var(--dim);margin-bottom:3rem;display:flex;gap:1.5rem;flex-wrap:wrap} +nav a{color:var(--dim);text-decoration:none;border-bottom:1px solid transparent} +nav a:hover{color:var(--amber);border-bottom-color:var(--amber)} +h1{font-size:clamp(1.3rem,3.6vw,2.1rem);font-weight:400;line-height:1.2;margin:0 0 .6rem;letter-spacing:-.01em} +h2{font-size:.78rem;letter-spacing:.22em;text-transform:uppercase;color:var(--dim);font-weight:400; +margin:3.5rem 0 1rem;padding-bottom:.5rem;border-bottom:1px solid var(--rule)} +.sub{color:var(--dim);font-size:.85rem;margin:0 0 2.5rem} +.score{display:flex;align-items:baseline;gap:1rem;flex-wrap:wrap;margin:0 0 .5rem} +.score .n{font-size:clamp(2.6rem,9vw,4.4rem);line-height:1;color:var(--amber);letter-spacing:-.03em} +.score .g{font-size:1rem;color:var(--dim);letter-spacing:.2em} +.lede{font-size:1.02rem;margin:1.5rem 0 0;padding-left:1rem;border-left:2px solid var(--amber);color:var(--bone)} +table{width:100%;border-collapse:collapse;font-size:.84rem;margin:0} +th{text-align:left;color:var(--dim);font-weight:400;font-size:.7rem;letter-spacing:.14em;text-transform:uppercase; +padding:.5rem .6rem;border-bottom:1px solid var(--rule)} +td{padding:.55rem .6rem;border-bottom:1px solid #1b1e1b;vertical-align:top} +td.num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap} +.bar{display:inline-block;height:7px;background:var(--amber);vertical-align:middle;border-radius:1px} +.bar.low{background:var(--bad)} +.weak td{background:rgba(201,86,63,.07)} +.sev{font-size:.66rem;letter-spacing:.12em;text-transform:uppercase;padding:.1rem .4rem;border:1px solid var(--rule)} +.sev.high{border-color:var(--bad);color:var(--bad)} +.sev.medium{border-color:var(--amber);color:var(--amber)} +.sev.low,.sev.info{color:var(--dim)} +.tier{color:var(--dim);font-size:.72rem} +a{color:var(--amber);text-decoration:none;border-bottom:1px solid rgba(217,164,65,.35)} +a:hover{border-bottom-color:var(--amber)} +.note{color:var(--dim);font-size:.8rem;line-height:1.65;margin:1rem 0 0} +pre{overflow-x:auto;background:#111413;border:1px solid var(--rule);padding:1rem;font-size:.76rem;line-height:1.5;color:var(--bone)} +code{font-size:.86em;color:var(--bone)} +footer{margin-top:5rem;padding-top:1.5rem;border-top:1px solid var(--rule);color:var(--dim);font-size:.75rem} +`; + +const NAV = ``; + +function page(title, body) { + return ` + + +${esc(title)} + +
${NAV}${body} +
Generated from bigtech.db on ${esc(cat.generated_at.slice(0, 10))}. +Method ${esc(cat.method_version)}. Every number recomputes from its evidence or the build fails.
+
`; +} + +// ------------------------------------------------------------------ report +function renderReport(a) { + const product = cat.products.find((p) => p.id === a.product_id) ?? {}; + const scores = cat.scores.filter((s) => s.assessment_id === a.id); + const evidence = cat.evidence.filter((e) => e.assessment_id === a.id); + const findings = cat.findings.filter((f) => f.assessment_id === a.id); + const maxW = Math.max(...scores.map((s) => s.weight)); + + const rows = scores.map((s) => { + const cls = s.dimension_id === a.weakest_dimension ? 'weak' : ''; + return ` + ${esc(s.label)} + ${s.weight} + ${s.value} + + `; + }).join(''); + + const evRows = evidence.map((e) => ` + ${esc(e.claim)} + T${e.tier} + ${e.artifact && e.artifact.startsWith('http') + ? `source` + : `${esc((e.artifact || '').split('/').slice(-1)[0])}`} + `).join(''); + + const fRows = findings.map((f) => ` + ${esc(f.severity)} + ${esc(f.title)}${f.cve ? ` ${esc(f.cve)}` : ''} + ${esc(f.status)} + `).join(''); + + const body = ` +

${esc(product.name)} ${esc(a.version)} on ${esc(a.platform)}

+

Assessed ${esc(a.assessed_on)} by CLU, Binary Ranch. Source commit +${esc((a.source_commit || '').slice(0, 12))}. Method ${esc(a.method_version)}.

+ +
${a.weighted_total}/ 100   GRADE ${esc(a.grade)}
+

${esc(a.headline)}

+ +

The score

+ + + ${rows} +
DimensionWeightScore
+

The weighted average is not the headline. The weakest dimension is, because a +high average with one bad rung is an average that hides the thing that will hurt you.

+ +

Findings

+ + + ${fRows} +
SeverityFindingStatus
+ +

Evidence

+ + + ${evRows} +
ClaimTierArtifact
+

Tier 1 is something we observed and saved. Tier 2 is a primary source anyone can open. +Tier 3 is credible second-hand. Tier 4 is a claim with no artifact, and no tier 4 claim is +allowed to move a score.

+ +

What was not tested

+

${esc(a.not_tested || 'Not recorded.')}

+ +

Check it yourself

+

The audit script that produced the tier 1 rows is public and re-runnable. +The database that holds this score is public. The build refuses to pass if the total does not +recompute from these weights and these scores.

+
git clone ssh://git@forge.binaryranch.com:2222/bunkhouse/bigtech-sucks.git
+cd bigtech-sucks && npm run db:build
`; + return page(`${product.name} scored ${a.weighted_total} — BigTech.sucks`, body); +} + +// ------------------------------------------------------------------ method +function renderMethod() { + const dims = cat.dimensions.map((d) => ` + ${esc(d.label)} + ${d.weight} + ${esc(d.anchor_10)} + `).join(''); + + const body = ` +

The method

+

How every score on this site is produced, and what we refuse to do to get one.

+ +

A privacy claim that cannot be checked is a slogan. We publish the method so a +stranger can catch us lying.

+ +

Eight dimensions, weighted to 100

+ + + ${dims} +
DimensionWeightWhat a 10 requires
+ +

Evidence tiers

+ + + + + + +
TierMeaning
T1We observed it, saved the artifact, and the procedure is re-runnable.
T2A primary source anyone can open: a vendor repository, a court filing, a regulator advisory.
T3Credible second-hand: reporting, an academic paper, an independent audit summary.
T4A claim with no artifact. Never allowed to move a score. It appears in an appendix, labelled, and that is all.
+ +

The caps

+

These are the only two places where a score is limited by something other than evidence. +Both exist because the alternative is pretending to know something we cannot.

+ +

Reproducible builds

+
no reproducible build        verifiability <= 3
+experimental, unverified     verifiability <= 6
+verified, bit-identical      verifiability <= 10
+

Reading the source proves what the code does. It does not prove the binary running on +your machine is that code. Reproducible builds are the only bridge, and nothing else is.

+ +

Closed source

+

Closed source is not penalised. It starts lower and climbs a public ladder. The ceiling +is the rung you are standing on.

+
L0 unattested    -> 3    nothing but your word
+L1 declared      -> 5    SBOM + signed hash + published destination allowlist
+L2 observed      -> 7    someone other than you watched this exact binary
+L3 reproducible  -> 9    anyone can rebuild it and get the same bytes
+L4 contested     -> 10   someone tried to break it and published the attempt
+

A court filing lifts the ceiling entirely, because it needs no vendor cooperation.

+ +

And the rule that makes it honest

+
a vendor running our harness produces a DECLARATION, not an OBSERVATION.
+

A self-run test is a claim about oneself, so it caps at L1. But L3 and L4 survive a +self-run, because a public rebuild recipe and a published adversarial review can be re-executed by +anyone. That is the whole escape hatch: reproducibility converts a claim into a check.

+ +

The dynamic test

+ + + + + + +
RunWhat it does
D1Cold idle. Fresh install, no account, one hour. Capture every packet.
D2Normal use, 24 hours. Capture all egress.
D3Device access trace: audio, camera, location, clipboard, contacts, screen.
D4Update cycle. Capture the channel, verify the signature, check the pinning.
+

The vendor publishes a destination allowlist. Every destination observed in D1 and D2 +must appear on it. Anything unlisted is a defect, regardless of what it turns out to be.

+ +

What this method cannot do

+

It cannot prove the absence of a backdoor. Rice's theorem makes non-trivial behavioural +properties of arbitrary programs undecidable, and a backdoor triggered by remote configuration or by +message content is invisible to static inspection.

+

So the honest claim is not purity. It is this: we can prove what a specific +build did while we watched, and we can make a false statement expensive to sign. An attestation +raises the cost of a backdoor and shortens its shelf life. It is not a certificate of innocence, and +anyone selling you one is selling you nothing.

+ +

Our own stack goes first

+

brainix will be scored by this instrument before it is advertised by it. "Zero telemetry" +will mean a captured packet log with nothing in it, published, dated, and re-runnable, or we do not get +to say it.

`; + return page('The method — BigTech.sucks', body); +} + +// ------------------------------------------------------------------ write +mkdirSync(join(PUB, 'report'), { recursive: true }); + +let written = 0; +for (const a of cat.assessments) { + const product = cat.products.find((p) => p.id === a.product_id); + if (!product) continue; + writeFileSync(join(PUB, 'report', `${a.product_id}.html`), renderReport(a)); + written++; +} +writeFileSync(join(PUB, 'method.html'), renderMethod()); + +console.log(`rendered ${written} report page(s) + method.html into packages/web/public/`); diff --git a/packages/core/src/data/generated/catalog.json b/packages/core/src/data/generated/catalog.json index 4bb0d3f..a3b185b 100644 --- a/packages/core/src/data/generated/catalog.json +++ b/packages/core/src/data/generated/catalog.json @@ -1,5 +1,5 @@ { - "generated_at": "2026-10-29T21:07:55.483Z", + "generated_at": "2026-10-29T21:22:40.574Z", "method_version": "btr-0.1", "dimensions": [ { @@ -2851,7 +2851,7 @@ ], "evidence": [ { - "id": 33, + "id": 44, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "local_data_exposure", "claim": "Attachments are stored unencrypted on the filesystem; the SQLCipher key is held by the OS keyring.", @@ -2862,7 +2862,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 34, + "id": 45, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "telemetry_egress", "claim": "Electron media permission defaults to false and audio is denied unless the user has enabled mediaPermissions.", @@ -2873,7 +2873,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 35, + "id": 46, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "telemetry_egress", "claim": "Zero analytics, tracker or crash-upload dependencies across 224 packages.", @@ -2884,7 +2884,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 36, + "id": 47, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "telemetry_egress", "claim": "Only two audio capture call sites exist and both are reachable only from an explicit UI action.", @@ -2895,7 +2895,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 37, + "id": 48, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "verifiability", "claim": "Signal states reproducible builds for macOS and Windows are not available, and the Linux build is experimental.", @@ -2906,7 +2906,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 38, + "id": 49, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "server_retention", "claim": "Grand jury subpoena response returned two timestamps and nothing else.", @@ -2917,7 +2917,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 39, + "id": 50, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "ownership_jurisdiction", "claim": "Signal Technology Foundation is a 501(c)(3) with EIN 82-4506840.", @@ -2928,7 +2928,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 40, + "id": 51, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "incident_record", "claim": "FBI and CISA PSA260626: Russian intelligence compromised individual Signal accounts via phishing and Backup Recovery Key theft, but NOT the encryption or the application itself.", @@ -2939,7 +2939,7 @@ "observed_at": "2026-10-29T15:26:00-05:00" }, { - "id": 41, + "id": 52, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "incident_record", "claim": "Signal statement, 28 April 2026: \"Signal was not hacked, in that our encryption, infrastructure, and the integrity of the app code was not compromised.\" Additional linkage confirmations shipped 13 May 2026.", @@ -2950,7 +2950,7 @@ "observed_at": "2026-10-29T15:26:00-05:00" }, { - "id": 42, + "id": 53, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "ownership_jurisdiction", "claim": "Open Technology Fund funded Open Whisper Systems $2,955,000 across 2013 to 2016, itemised on OTF own project page. This is the factual core under the \"US government funded Signal\" claim, and it is already reflected in the two points docked on this dimension.", @@ -2961,7 +2961,7 @@ "observed_at": "2026-10-29T15:26:00-05:00" }, { - "id": 43, + "id": 54, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "user_control_exit", "claim": "Signal publicly committed to leaving the UK (2023, Online Safety Act) and Sweden (Feb 2025) rather than weaken encryption. A vendor that threatens to lose a market is behaving incompatibly with a secret backdoor.", @@ -2974,7 +2974,7 @@ ], "findings": [ { - "id": 17, + "id": 21, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "high", "title": "Received attachments are stored unencrypted on disk", @@ -2983,7 +2983,7 @@ "cve": "CVE-2023-24069" }, { - "id": 18, + "id": 22, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "medium", "title": "No verified reproducible build for the Linux package", @@ -2992,7 +2992,7 @@ "cve": null }, { - "id": 19, + "id": 23, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "medium", "title": "Local database key is held in the OS keyring", @@ -3001,7 +3001,7 @@ "cve": null }, { - "id": 20, + "id": 24, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "low", "title": "Registration requires a phone number", diff --git a/packages/core/src/data/generated/catalog.ts b/packages/core/src/data/generated/catalog.ts index 44d54a6..9041a4d 100644 --- a/packages/core/src/data/generated/catalog.ts +++ b/packages/core/src/data/generated/catalog.ts @@ -39,7 +39,7 @@ export interface CatalogDimension { } export const catalog = { - "generated_at": "2026-10-29T21:07:55.483Z", + "generated_at": "2026-10-29T21:22:40.574Z", "method_version": "btr-0.1", "dimensions": [ { @@ -2891,7 +2891,7 @@ export const catalog = { ], "evidence": [ { - "id": 33, + "id": 44, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "local_data_exposure", "claim": "Attachments are stored unencrypted on the filesystem; the SQLCipher key is held by the OS keyring.", @@ -2902,7 +2902,7 @@ export const catalog = { "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 34, + "id": 45, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "telemetry_egress", "claim": "Electron media permission defaults to false and audio is denied unless the user has enabled mediaPermissions.", @@ -2913,7 +2913,7 @@ export const catalog = { "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 35, + "id": 46, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "telemetry_egress", "claim": "Zero analytics, tracker or crash-upload dependencies across 224 packages.", @@ -2924,7 +2924,7 @@ export const catalog = { "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 36, + "id": 47, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "telemetry_egress", "claim": "Only two audio capture call sites exist and both are reachable only from an explicit UI action.", @@ -2935,7 +2935,7 @@ export const catalog = { "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 37, + "id": 48, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "verifiability", "claim": "Signal states reproducible builds for macOS and Windows are not available, and the Linux build is experimental.", @@ -2946,7 +2946,7 @@ export const catalog = { "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 38, + "id": 49, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "server_retention", "claim": "Grand jury subpoena response returned two timestamps and nothing else.", @@ -2957,7 +2957,7 @@ export const catalog = { "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 39, + "id": 50, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "ownership_jurisdiction", "claim": "Signal Technology Foundation is a 501(c)(3) with EIN 82-4506840.", @@ -2968,7 +2968,7 @@ export const catalog = { "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 40, + "id": 51, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "incident_record", "claim": "FBI and CISA PSA260626: Russian intelligence compromised individual Signal accounts via phishing and Backup Recovery Key theft, but NOT the encryption or the application itself.", @@ -2979,7 +2979,7 @@ export const catalog = { "observed_at": "2026-10-29T15:26:00-05:00" }, { - "id": 41, + "id": 52, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "incident_record", "claim": "Signal statement, 28 April 2026: \"Signal was not hacked, in that our encryption, infrastructure, and the integrity of the app code was not compromised.\" Additional linkage confirmations shipped 13 May 2026.", @@ -2990,7 +2990,7 @@ export const catalog = { "observed_at": "2026-10-29T15:26:00-05:00" }, { - "id": 42, + "id": 53, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "ownership_jurisdiction", "claim": "Open Technology Fund funded Open Whisper Systems $2,955,000 across 2013 to 2016, itemised on OTF own project page. This is the factual core under the \"US government funded Signal\" claim, and it is already reflected in the two points docked on this dimension.", @@ -3001,7 +3001,7 @@ export const catalog = { "observed_at": "2026-10-29T15:26:00-05:00" }, { - "id": 43, + "id": 54, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "user_control_exit", "claim": "Signal publicly committed to leaving the UK (2023, Online Safety Act) and Sweden (Feb 2025) rather than weaken encryption. A vendor that threatens to lose a market is behaving incompatibly with a secret backdoor.", @@ -3014,7 +3014,7 @@ export const catalog = { ], "findings": [ { - "id": 17, + "id": 21, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "high", "title": "Received attachments are stored unencrypted on disk", @@ -3023,7 +3023,7 @@ export const catalog = { "cve": "CVE-2023-24069" }, { - "id": 18, + "id": 22, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "medium", "title": "No verified reproducible build for the Linux package", @@ -3032,7 +3032,7 @@ export const catalog = { "cve": null }, { - "id": 19, + "id": 23, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "medium", "title": "Local database key is held in the OS keyring", @@ -3041,7 +3041,7 @@ export const catalog = { "cve": null }, { - "id": 20, + "id": 24, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "low", "title": "Registration requires a phone number", diff --git a/packages/web/public/catalog.json b/packages/web/public/catalog.json index 4bb0d3f..a3b185b 100644 --- a/packages/web/public/catalog.json +++ b/packages/web/public/catalog.json @@ -1,5 +1,5 @@ { - "generated_at": "2026-10-29T21:07:55.483Z", + "generated_at": "2026-10-29T21:22:40.574Z", "method_version": "btr-0.1", "dimensions": [ { @@ -2851,7 +2851,7 @@ ], "evidence": [ { - "id": 33, + "id": 44, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "local_data_exposure", "claim": "Attachments are stored unencrypted on the filesystem; the SQLCipher key is held by the OS keyring.", @@ -2862,7 +2862,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 34, + "id": 45, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "telemetry_egress", "claim": "Electron media permission defaults to false and audio is denied unless the user has enabled mediaPermissions.", @@ -2873,7 +2873,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 35, + "id": 46, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "telemetry_egress", "claim": "Zero analytics, tracker or crash-upload dependencies across 224 packages.", @@ -2884,7 +2884,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 36, + "id": 47, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "telemetry_egress", "claim": "Only two audio capture call sites exist and both are reachable only from an explicit UI action.", @@ -2895,7 +2895,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 37, + "id": 48, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "verifiability", "claim": "Signal states reproducible builds for macOS and Windows are not available, and the Linux build is experimental.", @@ -2906,7 +2906,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 38, + "id": 49, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "server_retention", "claim": "Grand jury subpoena response returned two timestamps and nothing else.", @@ -2917,7 +2917,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 39, + "id": 50, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "ownership_jurisdiction", "claim": "Signal Technology Foundation is a 501(c)(3) with EIN 82-4506840.", @@ -2928,7 +2928,7 @@ "observed_at": "2026-10-29T13:13:56-05:00" }, { - "id": 40, + "id": 51, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "incident_record", "claim": "FBI and CISA PSA260626: Russian intelligence compromised individual Signal accounts via phishing and Backup Recovery Key theft, but NOT the encryption or the application itself.", @@ -2939,7 +2939,7 @@ "observed_at": "2026-10-29T15:26:00-05:00" }, { - "id": 41, + "id": 52, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "incident_record", "claim": "Signal statement, 28 April 2026: \"Signal was not hacked, in that our encryption, infrastructure, and the integrity of the app code was not compromised.\" Additional linkage confirmations shipped 13 May 2026.", @@ -2950,7 +2950,7 @@ "observed_at": "2026-10-29T15:26:00-05:00" }, { - "id": 42, + "id": 53, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "ownership_jurisdiction", "claim": "Open Technology Fund funded Open Whisper Systems $2,955,000 across 2013 to 2016, itemised on OTF own project page. This is the factual core under the \"US government funded Signal\" claim, and it is already reflected in the two points docked on this dimension.", @@ -2961,7 +2961,7 @@ "observed_at": "2026-10-29T15:26:00-05:00" }, { - "id": 43, + "id": 54, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "dimension_id": "user_control_exit", "claim": "Signal publicly committed to leaving the UK (2023, Online Safety Act) and Sweden (Feb 2025) rather than weaken encryption. A vendor that threatens to lose a market is behaving incompatibly with a secret backdoor.", @@ -2974,7 +2974,7 @@ ], "findings": [ { - "id": 17, + "id": 21, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "high", "title": "Received attachments are stored unencrypted on disk", @@ -2983,7 +2983,7 @@ "cve": "CVE-2023-24069" }, { - "id": 18, + "id": 22, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "medium", "title": "No verified reproducible build for the Linux package", @@ -2992,7 +2992,7 @@ "cve": null }, { - "id": 19, + "id": 23, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "medium", "title": "Local database key is held in the OS keyring", @@ -3001,7 +3001,7 @@ "cve": null }, { - "id": 20, + "id": 24, "assessment_id": "A-2026-10-29-SIGNAL-DESKTOP", "severity": "low", "title": "Registration requires a phone number", diff --git a/packages/web/public/method.html b/packages/web/public/method.html new file mode 100644 index 0000000..7c76ddb --- /dev/null +++ b/packages/web/public/method.html @@ -0,0 +1,154 @@ + + + +The method — BigTech.sucks + +
+

The method

+

How every score on this site is produced, and what we refuse to do to get one.

+ +

A privacy claim that cannot be checked is a slogan. We publish the method so a +stranger can catch us lying.

+ +

Eight dimensions, weighted to 100

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DimensionWeightWhat a 10 requires
Telemetry and egress25Published destination allowlist; cold idle produces zero unlisted packets, independently confirmed.
Verifiability20Reproducible build verified on the scored platform.
Server-side retention15Subpoena answer is two timestamps or an empty set.
Ownership, jurisdiction, business model12Nonprofit or cooperative, no ad model, strong process protections.
Local data exposure10All artifacts encrypted at rest under a user-presence key.
Dependency surface8Small audited dependency tree, signed and pinned update channel.
User control and exit5Usable export, real deletion, no identity hostage-taking.
Incident record5Flaws found, disclosed honestly, fixed fast.
+ +

Evidence tiers

+ + + + + + +
TierMeaning
T1We observed it, saved the artifact, and the procedure is re-runnable.
T2A primary source anyone can open: a vendor repository, a court filing, a regulator advisory.
T3Credible second-hand: reporting, an academic paper, an independent audit summary.
T4A claim with no artifact. Never allowed to move a score. It appears in an appendix, labelled, and that is all.
+ +

The caps

+

These are the only two places where a score is limited by something other than evidence. +Both exist because the alternative is pretending to know something we cannot.

+ +

Reproducible builds

+
no reproducible build        verifiability <= 3
+experimental, unverified     verifiability <= 6
+verified, bit-identical      verifiability <= 10
+

Reading the source proves what the code does. It does not prove the binary running on +your machine is that code. Reproducible builds are the only bridge, and nothing else is.

+ +

Closed source

+

Closed source is not penalised. It starts lower and climbs a public ladder. The ceiling +is the rung you are standing on.

+
L0 unattested    -> 3    nothing but your word
+L1 declared      -> 5    SBOM + signed hash + published destination allowlist
+L2 observed      -> 7    someone other than you watched this exact binary
+L3 reproducible  -> 9    anyone can rebuild it and get the same bytes
+L4 contested     -> 10   someone tried to break it and published the attempt
+

A court filing lifts the ceiling entirely, because it needs no vendor cooperation.

+ +

And the rule that makes it honest

+
a vendor running our harness produces a DECLARATION, not an OBSERVATION.
+

A self-run test is a claim about oneself, so it caps at L1. But L3 and L4 survive a +self-run, because a public rebuild recipe and a published adversarial review can be re-executed by +anyone. That is the whole escape hatch: reproducibility converts a claim into a check.

+ +

The dynamic test

+ + + + + + +
RunWhat it does
D1Cold idle. Fresh install, no account, one hour. Capture every packet.
D2Normal use, 24 hours. Capture all egress.
D3Device access trace: audio, camera, location, clipboard, contacts, screen.
D4Update cycle. Capture the channel, verify the signature, check the pinning.
+

The vendor publishes a destination allowlist. Every destination observed in D1 and D2 +must appear on it. Anything unlisted is a defect, regardless of what it turns out to be.

+ +

What this method cannot do

+

It cannot prove the absence of a backdoor. Rice's theorem makes non-trivial behavioural +properties of arbitrary programs undecidable, and a backdoor triggered by remote configuration or by +message content is invisible to static inspection.

+

So the honest claim is not purity. It is this: we can prove what a specific +build did while we watched, and we can make a false statement expensive to sign. An attestation +raises the cost of a backdoor and shortens its shelf life. It is not a certificate of innocence, and +anyone selling you one is selling you nothing.

+ +

Our own stack goes first

+

brainix will be scored by this instrument before it is advertised by it. "Zero telemetry" +will mean a captured packet log with nothing in it, published, dated, and re-runnable, or we do not get +to say it.

+
Generated from bigtech.db on 2026-10-29. +Method btr-0.1. Every number recomputes from its evidence or the build fails.
+
\ No newline at end of file diff --git a/packages/web/public/oath.json b/packages/web/public/oath.json index 2ff4277..1ecba6e 100644 --- a/packages/web/public/oath.json +++ b/packages/web/public/oath.json @@ -1,9 +1,9 @@ { - "digest": "0dc5a4129eef262900a70dbdc743d99aa7fb50bbd778cf7ab58ebbbe4ac2308a", + "digest": "fcc6032021e38bef4c5d2122c640a82cd5d066b3a8e9b7b378b0f31f2133e51c", "algorithm": "sha256", "file": "catalog.json", "byte_length": 82952, - "rebuilt_at": "2026-10-29T21:07:55.485Z", + "rebuilt_at": "2026-10-29T21:22:40.576Z", "method_version": "btr-0.1", "products": 123, "assessed": 1 diff --git a/packages/web/public/report/signal-desktop.html b/packages/web/public/report/signal-desktop.html new file mode 100644 index 0000000..3db6f5d --- /dev/null +++ b/packages/web/public/report/signal-desktop.html @@ -0,0 +1,189 @@ + + + +Signal Desktop scored 76.4 — BigTech.sucks + +
+

Signal Desktop 8.36.0-alpha.1 on

+

Assessed 2026-10-29 by CLU, Binary Ranch. Source commit +5dad34ad5ea1. Method btr-0.1.

+ +
76.4/ 100   GRADE B
+

The strongest transport on the internet, sitting behind the weakest desktop client we have scored.

+ +

The score

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DimensionWeightScore
Telemetry and egress259
Verifiability206
Server-side retention1510
Ownership, jurisdiction, business model128
Local data exposure105
Dependency surface86
User control and exit57
Incident record58
+

The weighted average is not the headline. The weakest dimension is, because a +high average with one bad rung is an average that hides the thing that will hurt you.

+ +

Findings

+ + + + + + + + + + + + + + + + + + + +
SeverityFindingStatus
highReceived attachments are stored unencrypted on disk CVE-2023-24069by_design
mediumNo verified reproducible build for the Linux packageopen
mediumLocal database key is held in the OS keyringaccepted
lowRegistration requires a phone numberaccepted
+ +

Evidence

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ClaimTierArtifact
Attachments are stored unencrypted on the filesystem; the SQLCipher key is held by the OS keyring.T101-capture-sites.txt
Electron media permission defaults to false and audio is denied unless the user has enabled mediaPermissions.T102-permissions.txt
Zero analytics, tracker or crash-upload dependencies across 224 packages.T105-dependencies.txt
Only two audio capture call sites exist and both are reachable only from an explicit UI action.T103-call-path.txt
Signal states reproducible builds for macOS and Windows are not available, and the Linux build is experimental.T2source
Grand jury subpoena response returned two timestamps and nothing else.T2source
Signal Technology Foundation is a 501(c)(3) with EIN 82-4506840.T2source
FBI and CISA PSA260626: Russian intelligence compromised individual Signal accounts via phishing and Backup Recovery Key theft, but NOT the encryption or the application itself.T2source
Signal statement, 28 April 2026: "Signal was not hacked, in that our encryption, infrastructure, and the integrity of the app code was not compromised." Additional linkage confirmations shipped 13 May 2026.T2source
Open Technology Fund funded Open Whisper Systems $2,955,000 across 2013 to 2016, itemised on OTF own project page. This is the factual core under the "US government funded Signal" claim, and it is already reflected in the two points docked on this dimension.T2source
Signal publicly committed to leaving the UK (2023, Online Safety Act) and Sweden (Feb 2025) rather than weaken encryption. A vendor that threatens to lose a market is behaving incompatibly with a secret backdoor.T2source
+

Tier 1 is something we observed and saved. Tier 2 is a primary source anyone can open. +Tier 3 is credible second-hand. Tier 4 is a claim with no artifact, and no tier 4 claim is +allowed to move a score.

+ +

What was not tested

+

No live account was used. No packet capture was run (D1 to D4 not executed, this is a source audit only). Android and iOS clients not assessed. No attempt to verify the shipped .deb against a local rebuild.

+ +

Check it yourself

+

The audit script that produced the tier 1 rows is public and re-runnable. +The database that holds this score is public. The build refuses to pass if the total does not +recompute from these weights and these scores.

+
git clone ssh://git@forge.binaryranch.com:2222/bunkhouse/bigtech-sucks.git
+cd bigtech-sucks && npm run db:build
+ +
\ No newline at end of file