{
 "number": 35984,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/35984",
 "title": "sign: skip signing SIGHASH_SINGLE inputs with no corresponding output",
 "author": "furszy",
 "author_association": "MEMBER",
 "created_at": "2026-08-15T18:17:13Z",
 "updated_at": "2026-09-14T02:38:06Z",
 "age_days": 32,
 "draft": false,
 "labels": [],
 "milestone": null,
 "base": "master",
 "head_sha": "8df006f233839736b6d7b856bcf8673526c7acef",
 "head_ref": "2026_psbt_sighash-single",
 "head_repo": "furszy/bitcoin-core",
 "head_history": [
  {
   "t": "2026-08-15T18:57:34Z",
   "sha": "0fa39483fb891d7dd0e35942c927646756550132"
  },
  {
   "t": "2026-09-13T14:57:14Z",
   "sha": "8df006f233839736b6d7b856bcf8673526c7acef"
  }
 ],
 "additions": 37,
 "deletions": 8,
 "changed_files": 2,
 "commit_count": 1,
 "size_bucket": "S",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "concept_ack": [
     {
      "login": "l0rinc",
      "url": "https://github.com/bitcoin/bitcoin/pull/35984#issuecomment-5303944689"
     }
    ],
    "stale_ack": [
     {
      "login": "achow101",
      "url": "https://github.com/bitcoin/bitcoin/pull/35984#issuecomment-5321304712"
     }
    ]
   },
   "conflicts": []
  }
 },
 "acks_parsed": {
  "l0rinc": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-08-15T19:49:15Z",
   "stale": false
  },
  "achow101": {
   "kind": "ack",
   "hash": "0fa39483fb891d7dd0e35942c927646756550132",
   "t": "2026-08-17T23:09:49Z",
   "stale": true
  }
 },
 "acks_tally": {
  "ack": 0,
  "stale_ack": 1,
  "concept_ack": 1,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "achow101",
   "l0rinc"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-09-13T14:57:14Z",
  "last_reviewer_activity": "2026-08-17T23:09:49Z",
  "last_reviewer": "achow101",
  "author_silent_days": 4,
  "waiting_on_author_days": 0,
  "days_since_update": 3
 },
 "refs": {
  "mentioned": [
   35977
  ],
  "depends_on": [],
  "fixes": [
   35977
  ],
  "linked_issues": [
   {
    "number": 35977,
    "type": "issue",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "psbt: refuse transaction-independent `SIGHASH_SINGLE` signatures"
   }
  ],
  "references": [
   {
    "number": 35977,
    "type": "issue",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "psbt: refuse transaction-independent `SIGHASH_SINGLE` signatures"
   }
  ],
  "conflicts": []
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [],
 "body": "`SIGHASH_SINGLE` only commits to the output at the input's index. If the output at such\nposition doesn't exist, it commits to no output at all (legacy uses a fixed sighash of 1, segwit\nv0 zeroes `hashOutputs`), which means the signature stays valid even when outputs are\nswapped, which is a footgun that lets funds be redirected without the owner's consent.\n\n`SignTransaction()` already skipped these inputs, but `SignPSBTInput()` did not, so\n`walletprocesspsbt` signed them. This moves the check into the `CreateSig` so both\npaths, and any future one, skip producing the detached signature.\n\nNote: if there is a valid use for the segwit v0 case, I would rather re-allow it through\nan explicit opt-in arg than by default, so it is always a deliberate choice.\n\nFixes #35977",
 "commits": [
  {
   "sha": "8df006f233839736b6d7b856bcf8673526c7acef",
   "date": "2026-09-13T14:56:39Z",
   "message": "wallet: skip signing SIGHASH_SINGLE inputs with no corresponding output\n\nSIGHASH_SINGLE only commits to the output at the input's index. If the\noutput at such position doesn't exist, it commits to no output at all\n(legacy uses a fixed sighash of 1, segwit v0 zeroes hashOutputs), which\nmeans the signature stays valid even when outputs are swapped, which\nis a footgun that lets funds be redirected without the owner's consent.\n\nSignTransaction() already skipped these inputs, but SignPSBTInput()\ndid not, so walletprocesspsbt signed them. This moves the check into\nthe CreateSig so both paths, and any future one, skip producing the\ndetached signature."
  }
 ],
 "timeline": [
  {
   "t": "2026-08-15T18:57:34Z",
   "kind": "force_push",
   "who": "furszy",
   "commit": "0fa39483fb891d7dd0e35942c927646756550132"
  },
  {
   "t": "2026-08-15T18:59:21Z",
   "kind": "comment",
   "who": "l0rinc",
   "assoc": "MEMBER",
   "text": "Thanks for pushing a fix for #35977 so quickly (with extra `segwit-v0` coverage, guess you rediscovered it independently).\nCould you add `Fixes #35977` to the PR description so the issue auto-closes on merge?"
  },
  {
   "t": "2026-08-15T19:25:15Z",
   "kind": "comment",
   "who": "furszy",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nFunny, I didn't check the open issues, only PRs. Done."
  },
  {
   "t": "2026-08-15T19:49:15Z",
   "kind": "comment",
   "who": "l0rinc",
   "assoc": "MEMBER",
   "text": "Concept ACK\nIf you think it would help, consider adding a [characterization test](https://github.com/bitcoin/bitcoin/pull/35260) commit before the fix commit to document the previous behavior and to simplify the fix commit."
  },
  {
   "t": "2026-08-17T23:09:49Z",
   "kind": "comment",
   "who": "achow101",
   "assoc": "MEMBER",
   "text": "ACK 0fa39483fb891d7dd0e35942c927646756550132"
  },
  {
   "t": "2026-09-13T14:57:14Z",
   "kind": "force_push",
   "who": "furszy",
   "commit": "8df006f233839736b6d7b856bcf8673526c7acef"
  }
 ],
 "labels_log": [
  {
   "t": "2026-08-15T18:57:59Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-15T20:21:19Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-07T22:32:12Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-13T15:42:45Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  }
 ],
 "state_log": [],
 "text_chars": 2052,
 "text_tokens_estimate": 513,
 "changed_paths": [
  "src/script/sign.cpp",
  "test/functional/rpc_psbt.py"
 ],
 "files": [
  {
   "path": "src/script/sign.cpp",
   "add": 6,
   "del": 6
  },
  {
   "path": "test/functional/rpc_psbt.py",
   "add": 31,
   "del": 2
  }
 ],
 "test_lines": 33,
 "git": {
  "head": "8df006f233839736b6d7b856bcf8673526c7acef",
  "head_matches_backup": true,
  "base": "17817818da3cb67c95320b7a5d4d69bd649c1fbf",
  "commits": [
   {
    "sha": "8df006f233",
    "subject": "wallet: skip signing SIGHASH_SINGLE inputs with no corresponding output",
    "files": 2,
    "add": 37,
    "del": 8
   }
  ],
  "patch_truncated": false
 },
 "input_hash": "16158cfd3cbc4c55",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}