{
 "number": 36293,
 "input_hash": "6d4d254e95a172af",
 "model": "ledger",
 "prompt_hash": null,
 "created": "2026-10-05T01:16:01+00:00",
 "result": {
  "summary": "Excludes expired and revoked GPG signatures from counting toward the binary verification quorum in `contrib/verify-binaries/verify.py` by default. Adds an `--allow-expired` CLI flag and `BINVERIFY_ALLOW_EXPIRED` environment variable to permit expired keys when verifying older releases, while keeping revoked signatures unconditionally excluded. Adds parsing for `KEYREVOKED` status records, ensures revocation takes precedence over expiration, and reports expired signatures in a dedicated `expired_sigs` JSON field.",
  "problem": "`contrib/verify-binaries/verify.py` treats signatures from expired or revoked keys as valid signatures satisfying `--min-good-sigs`. A verification run can therefore pass and report binaries as verified even if all supplied signatures come from compromised or defunct keys.",
  "card": "Excludes expired and revoked GPG signatures from counting toward the binary verification threshold in contrib/verify-binaries/verify.py by default. Previously, release binary verification could succeed using only expired or revoked keys, an issue disclosed responsibly by the Red Team. To accommodate historical releases signed by keys that have since expired, an --allow-expired flag allows expired keys to count toward the threshold while revoked keys remain strictly excluded. Expired signatures are emitted separately in JSON output, and revocation status is given precedence over expiration.",
  "evidence": [
   "PR description: 'This was found and disclosed responsibly by the Red Team \ud83d\udfe5.'",
   "PR description: 'The binary verifier counts signatures from expired and revoked keys toward `--min-good-sigs`. Enough of these signatures can satisfy the threshold without any active signing key, and they are returned as good signatures.'"
  ],
  "scope_notes": "",
  "changed_since_previous": "Added explicit handling for GnuPG's `KEYREVOKED` status tag to prioritize revocation over expiration when both are reported, extracted `build_parser()` to facilitate testing, and added unit tests mocking GnuPG outputs across multiple environment and argument combinations.",
  "thread": {
   "last_event_at": "2026-09-25T09:31:25Z",
   "events": 14,
   "head_sha": "034271d4e1739347a31c64dbc4bfef8aa133ad1d",
   "schema_floor": 2,
   "schema": 2
  },
  "waiting_on": [
   {
    "at": null,
    "id": "",
    "on": "nothing",
    "url": null,
    "what": "all open items addressed and approved by reviewer"
   }
  ],
  "risk": {
   "level": "low",
   "touches": [
    "tooling",
    "tests",
    "docs"
   ],
   "why": "The change is confined to the release binary verification script in contrib; a bug could cause binary verification to reject valid signatures or accept invalid ones, but cannot impact the core node."
  },
  "discussion": {
   "author_status": "last statement processed 2026-09-25",
   "open_concerns": [],
   "resolved_concerns": [
    "willcl-ark: excluding expired keys by default could break verifying old releases or future verification of current releases when keys lapse (fixed by willcl-ark 2026-09-23)",
    "sedited: categorize sigs from expired keys separately and add a flag that allows the user to treat them as good (fixed by l0rinc 2026-09-18)",
    "willcl-ark: prompt or remind users that they should update keys periodically in local gpg (fixed by l0rinc 2026-09-25)",
    "willcl-ark: whether the test should have an assertion for expired_sigs fields (fixed by l0rinc 2026-09-25)",
    "willcl-ark: de-duplicate signatures by key or fingerprint rather than summing lengths (accepted by willcl-ark 2026-09-24)"
   ]
  },
  "reviewability": {
   "state": "Ready",
   "label": "Ready",
   "reason": "Nothing known that would invalidate a review now."
  },
  "agreement": {
   "state": "Strong",
   "summary": "Strong: substantive support, no open objection (willcl-ark)",
   "reason": "l0rinc pushed updates addressing the test assertions and adding a README note about updating keys. willcl-ark tested the changes across multiple releases and provided an ACK.",
   "evidence": [
    "willcl-ark: ACK \u2014 verified recent releases (22.1 through 31.1) with and without --allow-expired; all passed default quorum with local keyring without exception"
   ],
   "objections": [
    {
     "reviewer": "willcl-ark",
     "association": "MEMBER",
     "type": "objection",
     "kind": "approach",
     "harm": "excluding expired keys by default could break verifying old releases or future verification of current releases when keys lapse",
     "request": "",
     "question": "",
     "text": "excluding expired keys by default could break verifying old releases or future verification of current releases when keys lapse",
     "clears_with": "answer",
     "blocking": false,
     "status": "fixed",
     "status_note": "author implemented --allow-expired flag as suggested by sedited and willcl-ark, who found the end result decent",
     "cleared": true,
     "author_replied": true,
     "others_replied": true,
     "fix_pushed": true,
     "replies": [
      "c:5736621483",
      "c:5727040666"
     ],
     "evidence": "2026-09-18: 'will this break verifying old releases or current releases in the future?'",
     "url": "https://github.com/bitcoin/bitcoin/pull/36293#issuecomment-5726467814",
     "id": "c:5726467814",
     "at": "2026-09-18",
     "status_at": "2026-09-23",
     "status_by": "willcl-ark",
     "resolution_evidence": "2026-09-23: willcl-ark: 'The end result looks decent'",
     "pin": null,
     "from_schema": 2
    },
    {
     "reviewer": "sedited",
     "association": "MEMBER",
     "type": "suggestion",
     "kind": "interface",
     "harm": "",
     "request": "categorize sigs from expired keys separately and add a flag that allows the user to treat them as good",
     "question": "",
     "text": "categorize sigs from expired keys separately and add a flag that allows the user to treat them as good",
     "clears_with": "answer",
     "blocking": false,
     "status": "fixed",
     "status_note": "author added --allow-expired and reported expired sigs separately",
     "cleared": true,
     "author_replied": true,
     "others_replied": true,
     "fix_pushed": true,
     "replies": [
      "c:5736621483",
      "c:5727162821"
     ],
     "evidence": "2026-09-18: 'How about categorizing sigs from expired keys separately and adding a flag that allows the user to treat them as good?'",
     "url": "https://github.com/bitcoin/bitcoin/pull/36293#issuecomment-5727040666",
     "id": "c:5727040666",
     "at": "2026-09-18",
     "status_at": "2026-09-18",
     "status_by": "l0rinc",
     "resolution_evidence": "2026-09-18: l0rinc: 'Added `--allow-expired` for historical verification, with expired signatures reported separately'",
     "pin": null,
     "from_schema": 2
    },
    {
     "reviewer": "willcl-ark",
     "association": "MEMBER",
     "type": "suggestion",
     "kind": "interface",
     "harm": "",
     "request": "prompt or remind users that they should update keys periodically in local gpg",
     "question": "",
     "text": "prompt or remind users that they should update keys periodically in local gpg",
     "clears_with": "answer",
     "blocking": false,
     "status": "fixed",
     "status_note": "author added README note on stale local keyrings and reviewer approved",
     "cleared": true,
     "author_replied": true,
     "others_replied": false,
     "fix_pushed": true,
     "replies": [
      "r:5312073949"
     ],
     "evidence": "2026-09-24: 'I wonder if we should prompt/remind users that they should ideally update keys periodically.'",
     "url": "https://github.com/bitcoin/bitcoin/pull/36293#pullrequestreview-5301316723",
     "id": "r:5301316723",
     "at": "2026-09-24",
     "status_at": "2026-09-25",
     "status_by": "l0rinc",
     "resolution_evidence": "2026-09-25: l0rinc: 'The latest push adds a short README note that stale local keyrings may miss revocations and keyserver updates can reveal requested keys'",
     "pin": null,
     "from_schema": 2
    },
    {
     "reviewer": "willcl-ark",
     "association": "MEMBER",
     "type": "question",
     "kind": "correctness",
     "harm": "",
     "request": "",
     "question": "whether the test should have an assertion for expired_sigs fields",
     "text": "whether the test should have an assertion for expired_sigs fields",
     "clears_with": "answer",
     "blocking": false,
     "status": "fixed",
     "status_note": "author added test assertions for expired_sigs and reviewer approved",
     "cleared": true,
     "author_replied": true,
     "others_replied": false,
     "fix_pushed": true,
     "replies": [
      "rc:4100026521",
      "r:5312073949"
     ],
     "evidence": "2026-09-24: 'Do you think the test should have an assertion for these `expired_sigs` fields?'",
     "url": "https://github.com/bitcoin/bitcoin/pull/36293#discussion_r4091125514",
     "id": "rc:4091125514",
     "at": "2026-09-24",
     "status_at": "2026-09-25",
     "status_by": "l0rinc",
     "resolution_evidence": "2026-09-25: l0rinc: 'Sure, the `pub --json` test now checks that `expired_sigs` is a list, and the quorum test checks the expired signature\u2019s full representation.'",
     "pin": null,
     "from_schema": 2
    },
    {
     "reviewer": "willcl-ark",
     "association": "MEMBER",
     "type": "suggestion",
     "kind": "correctness",
     "harm": "",
     "request": "de-duplicate signatures by key or fingerprint rather than summing lengths",
     "question": "",
     "text": "de-duplicate signatures by key or fingerprint rather than summing lengths",
     "clears_with": "answer",
     "blocking": false,
     "status": "accepted",
     "status_note": "both agreed to leave deduplication for a follow-up PR",
     "cleared": true,
     "author_replied": true,
     "others_replied": false,
     "fix_pushed": false,
     "replies": [
      "rc:4100037715"
     ],
     "evidence": "2026-09-24: 'should we be de-duplicating by key or fingerprint perhaps?'",
     "url": "https://github.com/bitcoin/bitcoin/pull/36293#discussion_r4091158778",
     "id": "rc:4091158778",
     "at": "2026-09-24",
     "status_at": "2026-09-24",
     "status_by": "willcl-ark",
     "resolution_evidence": "2026-09-24: willcl-ark: 'Anyway, probably for a followup...'",
     "pin": null,
     "from_schema": 2
    }
   ],
   "support": [
    {
     "reviewer": "willcl-ark",
     "reason": "verified recent releases (22.1 through 31.1) with and without --allow-expired; all passed default quorum with local keyring without exception",
     "substantive": true,
     "verdict": "ACK",
     "id": "r:5315970979",
     "url": "https://github.com/bitcoin/bitcoin/pull/36293#pullrequestreview-5315970979",
     "at": "2026-09-25",
     "association": "MEMBER",
     "evidence": "tested",
     "areas": []
    }
   ],
   "participants": [
    {
     "login": "sedited",
     "stance": "neutral",
     "note": "suggested categorizing expired signatures separately and adding a flag to allow them",
     "association": "MEMBER",
     "comments": 1,
     "first": "2026-09-18",
     "last": "2026-09-18"
    },
    {
     "login": "willcl-ark",
     "stance": "support",
     "note": "ACKed after testing release verifications with and without --allow-expired",
     "association": "MEMBER",
     "comments": 7,
     "first": "2026-09-18",
     "last": "2026-09-25"
    }
   ],
   "derivation": "substantive support, no open objection (willcl-ark)",
   "model_state": null,
   "corrections": [],
   "notes": "l0rinc pushed updates addressing the test assertions and adding a README note about updating keys. willcl-ark tested the changes across multiple releases and provided an ACK."
  },
  "dependencies": {
   "depends_on": [],
   "enables": []
  },
  "categories": [
   {
    "name": "build",
    "member": true,
    "evidence": "Modifies `contrib/verify-binaries/`, the release-verification tooling under contrib that guards release integrity.",
    "band": "P2",
    "reason_tag": "bug fix",
    "score": 0.65,
    "factors": {
     "bug_severity": 2,
     "leverage": 0,
     "performance": 0,
     "security_stability": 2,
     "user_value": 1
    },
    "rationale": "Fixes a security flaw where expired and revoked GPG keys satisfied the release verification quorum. As reported by the Red Team disclosure, the verifier counted revoked keys toward `--min-good-sigs`, which could allow binaries to pass verification even if all signatures were from compromised keys."
   },
   {
    "name": "tools",
    "member": true,
    "evidence": "Carries the Scripts and tools label and modifies `contrib/verify-binaries/verify.py` and its tests.",
    "band": "P2",
    "reason_tag": "bug fix",
    "score": 0.65,
    "factors": {
     "bug_severity": 2,
     "leverage": 0,
     "performance": 0,
     "security_stability": 2,
     "user_value": 1
    },
    "rationale": "Corrects key-validation logic in a critical contrib verification tool. The script previously counted expired and revoked keys as good signatures toward quorum; this change excludes inactive keys by default while adding `--allow-expired` for older releases."
   }
  ],
  "confidence": "high",
  "uncertainties": [],
  "needs": []
 },
 "cost_usd": 0.0,
 "source": {
  "record": "2026-10-05T01:16:01+00:00",
  "code": "2026-09-25T01:29:47+00:00",
  "judgments": 2
 }
}