From e5028c9677ef1af86773dcfa64aa753d35f05e56 Mon Sep 17 00:00:00 2001 From: Ben Westgate Date: Fri, 25 Sep 2026 11:21:52 -0500 Subject: [PATCH 1/8] docs: Define trusted computer boundary Make the secret-output invariant literal about intentional recovery/export output, define the trusted-computer boundary consistently, and warn that shell command text can be retained even when stdin is safe from argv exposure. Update the shared CLI safety footer and its exact-help regression. Validation: focused help regression; Ruff check/format; strict mypy for the parser; git diff --check. The full generic-HRP module still reaches the pre-existing bip32 test dependency tracked by #3/#6 and fixed by #7. fixes #4 --- SECURITY.md | 26 +++++++++++++++++++------- docs/security/invariants.md | 12 ++++++++---- docs/security/model.md | 22 +++++++++++++++++++--- docs/user/guide.md | 20 ++++++++++++++------ src/codex32/_cli_parser.py | 5 +++-- tests/test_generic_hrp.py | 5 +++-- 6 files changed, 66 insertions(+), 24 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 7514e1b7..c540b668 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,9 +1,15 @@ # Security -codex32 handles wallet recovery material. Use a trusted computer and have the +codex32 handles wallet recovery material. A **trusted computer** is under your +exclusive control, is not known or suspected to be compromised, and runs an +operating system and other software you trust for the operation. For wallet +work, that trusted software includes Python, codex32, the terminal, +`bitcoin-cli`, Bitcoin Core, and their relevant configuration. Wallet encryption, +application permissions, and RPC authentication do not make a compromised +computer trusted. Have the software and recovery plan reviewed before relying on it with funds. For -stronger isolation, use codex32 and the Bitcoin Core signing wallet only on a -computer kept permanently offline. +stronger isolation, keep the trusted computer disconnected from every network +before, while, and after it handles private recovery or signing material. A valid checksum detects many copying mistakes. It does not prove that a backup belongs to your wallet. A correction is only a suggestion; compare it with the @@ -11,10 +17,16 @@ physical backup and wallet information kept elsewhere. Python, your terminal, and your operating system may retain secret text in memory or scrollback. codex32 does not intentionally save secrets and keeps -them out of command arguments and normal machine output, but it cannot -guarantee that every copy is erased from swap, hibernation data, or crash -dumps. Using Tails and shutting down when finished helps mitigate this Python -limitation. +them out of command arguments, logs, and unrelated output. Commands that create, +recover, derive, correct, or explicitly export recovery material intentionally +display it when that is their purpose. codex32 cannot guarantee that every copy +is erased from swap, hibernation data, or crash dumps. Using Tails and shutting +down when finished helps mitigate this Python limitation. + +Run a command first and enter recovery material at its prompt, or redirect its +standard input from a separately protected source. Do not embed recovery text in +shell command text: shell history, terminal logging, wrappers, and process +tooling may retain it even though codex32 never receives it as an argument. ## Report a security problem diff --git a/docs/security/invariants.md b/docs/security/invariants.md index be5ed482..51aa9c34 100644 --- a/docs/security/invariants.md +++ b/docs/security/invariants.md @@ -31,8 +31,12 @@ and evidence. warning and literal `YES` confirmation for every HRP. The bound includes all admitted classes ranked equal to or better than the candidate, independently of execution order. -6. Secrets stay out of arguments, logs, ordinary output, and public transfers. - During wallet setup, codex32 transfers the master xprv only through child stdin. +6. Secrets stay out of command arguments, logs, unrelated output, and public + transfers. Commands whose purpose is to create, recover, derive, correct, or + explicitly export recovery material may intentionally display that material + to the operator. During wallet setup, codex32 transfers the master xprv only + through child stdin. Private descriptors exist only in Python memory and child + stdin. 7. Bitcoin Core chains are discovered before entropy or recovery input. The operator confirms an eligible descriptor wallet by exact name. 8. Wallet state is revalidated before handing Core the master key. Core must @@ -41,8 +45,8 @@ and evidence. and verified on every exit path. 10. External text, Core output, public wallet data, and PSBTs are untrusted. 11. Only Bitcoin Core descriptor wallets sign with codex32-derived keys. - Sensitive operations use only codex32 or Core on malware-free computers - with trusted software. + Sensitive operations use only codex32 or Core on a trusted computer as + defined by the security model. 12. Offline hosts disable every network path, including Ethernet, internet, Tor, Wi-Fi, Bluetooth, and cellular. Online Core nodes synchronize before their balances or history are trusted. diff --git a/docs/security/model.md b/docs/security/model.md index de77db4d..d7be9ab8 100644 --- a/docs/security/model.md +++ b/docs/security/model.md @@ -31,13 +31,21 @@ fingerprints, and wallet history cannot spend funds but remain privacy-sensitive ## Operator assumptions +A **trusted computer** is under the operator's exclusive control, is not known +or suspected to be compromised, and runs an operating system and other software +the operator trusts for the operation. For codex32 wallet work, that trusted +software includes the Python environment, codex32, the terminal, `bitcoin-cli`, +Bitcoin Core, and their relevant configuration. An offline trusted computer +remains disconnected from every network before, while, and after it handles +private recovery or signing material. Wallet encryption, application +permissions, and RPC authentication do not make a compromised computer trusted. + The operator must: - use only Bitcoin Core descriptor wallets to sign with keys derived from a codex32 master seed; -- use computers believed malware-free and whose other software is trusted for - all codex32 operations and for wallet initialization and signing with Bitcoin - Core; +- use only trusted computers as defined above for codex32 operations, wallet + initialization, and signing with Bitcoin Core; - disconnect every computer used for offline codex32 or signing work from all network paths, including Ethernet, internet, Tor, Wi-Fi, Bluetooth, and cellular; @@ -53,6 +61,14 @@ The operator must: - never put recovery text in command arguments or transfer a master seed, share, xprv, or private descriptor through QR or a network service. +`create`, `secret`, `share`, `correct`, and `xprv` can intentionally display +secret-bearing recovery material because producing or exporting that material is +their purpose. This is distinct from accidental disclosure: unrelated status, +diagnostic, logging, and wallet-integration output must not reveal secrets. +Prompted input and standard-input redirection keep recovery text out of process +arguments, but the operator must also keep the text out of shell command text; +shell history, terminal logging, wrappers, or process tooling may retain it. + ## Security limitations - Python cannot guarantee zeroization, constant-time execution, locked memory, diff --git a/docs/user/guide.md b/docs/user/guide.md index 422ec998..edcef9a9 100644 --- a/docs/user/guide.md +++ b/docs/user/guide.md @@ -87,16 +87,24 @@ codex32 detects and reports the local Bitcoin Core network. You do not need to change `bitcoin.conf` when using the standard local data directory and RPC port. -Use a computer you believe is malware-free and whose other software you trust. -Only codex32 and Bitcoin Core should perform recovery, derivation, wallet -initialization, or signing. The QR tools below transport only public -descriptors or PSBTs. +Use a trusted computer: one under your exclusive control, not known or suspected +to be compromised, with its operating system, Python environment, terminal, +codex32, `bitcoin-cli`, Bitcoin Core, and relevant configuration trusted for the +operation. Wallet encryption or RPC authentication does not make a compromised +computer safe. An offline trusted computer stays disconnected from every network +before, while, and after it handles private recovery or signing material. Only +codex32 and Bitcoin Core should perform recovery, derivation, wallet +initialization, or signing. The QR tools below transport only public descriptors +or PSBTs. Bitcoin Core wallet encryption is strongly recommended. Bitcoin Core owns the passphrase and its prompts; codex32 never asks for, reads, or forwards it. -Do not type recovery text on the same line as a command. Run the command first, -then enter a master seed or shares on the separate `>` line when prompted. +Do not type recovery text on the same line as a command: shell history, terminal +logging, wrappers, or process tooling may retain the command text. Run the +command first, then enter a master seed or shares on the separate `>` line when +prompted. Standard-input redirection also keeps recovery text out of process +arguments, but protect the redirected source separately. This keeps a 48-character string grouped in fours within an 80-column terminal. Later share prompts may show a fixed common header after `>`. Never photograph recovery text or put it in a website, chat, cloud clipboard, or online QR diff --git a/src/codex32/_cli_parser.py b/src/codex32/_cli_parser.py index c2472109..39a9415b 100644 --- a/src/codex32/_cli_parser.py +++ b/src/codex32/_cli_parser.py @@ -86,8 +86,9 @@ def parser(prog: str = "codex32", *, master_seed: bool = False) -> argparse.Argu if master_seed else "Check, correct, recover, and derive shares from codex32 backups." ), - epilog="Never include a secret or share in command arguments.\n" - "Enter it when prompted. Some commands also accept piped input.", + epilog="Never put a secret or share in command arguments or shell command text.\n" + "Enter it when prompted; some commands also accept redirected standard input.\n" + "Protect redirected sources separately: shells, terminals, and wrappers may retain text.", formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False, ) diff --git a/tests/test_generic_hrp.py b/tests/test_generic_hrp.py index 0cf4f801..b384ae63 100644 --- a/tests/test_generic_hrp.py +++ b/tests/test_generic_hrp.py @@ -125,8 +125,9 @@ def test_cli_split_and_unknown_neutral_summary() -> None: " create create or confirm a backup, or split an existing secret\n" " wallet restore a Bitcoin Core wallet\n" " xprv export the root extended private key\n\n" - "Never include a secret or share in command arguments.\n" - "Enter it when prompted. Some commands also accept piped input.\n" + "Never put a secret or share in command arguments or shell command text.\n" + "Enter it when prompted; some commands also accept redirected standard input.\n" + "Protect redirected sources separately: shells, terminals, and wrappers may retain text.\n" ) for command in ("check", "correct", "secret", "share"): assert command in generic_help and command in ms_help From 2a7f444364b99a4456c4cabaf8f84af49e354784 Mon Sep 17 00:00:00 2001 From: Ben Westgate Date: Sat, 26 Sep 2026 21:51:37 -0500 Subject: [PATCH 2/8] docs: keep CLI safety footer within 80 columns --- src/codex32/_cli_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codex32/_cli_parser.py b/src/codex32/_cli_parser.py index 39a9415b..12178945 100644 --- a/src/codex32/_cli_parser.py +++ b/src/codex32/_cli_parser.py @@ -88,7 +88,7 @@ def parser(prog: str = "codex32", *, master_seed: bool = False) -> argparse.Argu ), epilog="Never put a secret or share in command arguments or shell command text.\n" "Enter it when prompted; some commands also accept redirected standard input.\n" - "Protect redirected sources separately: shells, terminals, and wrappers may retain text.", + "Protect redirected files; shells and terminals may keep text.", formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False, ) From 599ae25bafe2dd761dc44d525c60a473a04eda0c Mon Sep 17 00:00:00 2001 From: Ben Westgate Date: Sat, 26 Sep 2026 21:52:10 -0500 Subject: [PATCH 3/8] test: match shortened CLI safety footer --- tests/test_generic_hrp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_generic_hrp.py b/tests/test_generic_hrp.py index b384ae63..41c5b2f6 100644 --- a/tests/test_generic_hrp.py +++ b/tests/test_generic_hrp.py @@ -127,7 +127,7 @@ def test_cli_split_and_unknown_neutral_summary() -> None: " xprv export the root extended private key\n\n" "Never put a secret or share in command arguments or shell command text.\n" "Enter it when prompted; some commands also accept redirected standard input.\n" - "Protect redirected sources separately: shells, terminals, and wrappers may retain text.\n" + "Protect redirected files; shells and terminals may keep text.\n" ) for command in ("check", "correct", "secret", "share"): assert command in generic_help and command in ms_help From 38bcceaf7a17a6f77954ab89c08d2b3cebe0bd3d Mon Sep 17 00:00:00 2001 From: Ben Westgate Date: Sat, 24 Oct 2026 02:57:01 -0500 Subject: [PATCH 4/8] docs: Make recovery safety advice clearer Use plain language in security guidance and CLI help. Keep the security model's detailed constraints and correct the help test. refs #4 --- SECURITY.md | 33 +++++++++++---------------------- docs/user/guide.md | 30 ++++++++++++------------------ src/codex32/_cli_parser.py | 5 ++--- tests/test_generic_hrp.py | 5 ++--- 4 files changed, 27 insertions(+), 46 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index c540b668..4d21bd26 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,32 +1,21 @@ # Security -codex32 handles wallet recovery material. A **trusted computer** is under your -exclusive control, is not known or suspected to be compromised, and runs an -operating system and other software you trust for the operation. For wallet -work, that trusted software includes Python, codex32, the terminal, -`bitcoin-cli`, Bitcoin Core, and their relevant configuration. Wallet encryption, -application permissions, and RPC authentication do not make a compromised -computer trusted. Have the -software and recovery plan reviewed before relying on it with funds. For -stronger isolation, keep the trusted computer disconnected from every network -before, while, and after it handles private recovery or signing material. +codex32 handles wallet backup and recovery secrets. Use a computer you control +and whose software you trust. Malware can steal secrets even when the wallet is +encrypted. Have the software and recovery plan reviewed before using real funds. +For stronger isolation, keep the computer offline until you shut it down. A valid checksum detects many copying mistakes. It does not prove that a backup belongs to your wallet. A correction is only a suggestion; compare it with the physical backup and wallet information kept elsewhere. -Python, your terminal, and your operating system may retain secret text in -memory or scrollback. codex32 does not intentionally save secrets and keeps -them out of command arguments, logs, and unrelated output. Commands that create, -recover, derive, correct, or explicitly export recovery material intentionally -display it when that is their purpose. codex32 cannot guarantee that every copy -is erased from swap, hibernation data, or crash dumps. Using Tails and shutting -down when finished helps mitigate this Python limitation. - -Run a command first and enter recovery material at its prompt, or redirect its -standard input from a separately protected source. Do not embed recovery text in -shell command text: shell history, terminal logging, wrappers, and process -tooling may retain it even though codex32 never receives it as an argument. +codex32 does not intentionally save secrets or put them in command arguments, +logs, or unrelated output. Commands that create or recover backups may display +the recovery text on purpose. Python and the operating system may retain copies +in memory, terminal scrollback, or disk. Tails and shutdown reduce this risk. + +Run a command first, then enter your recovery text when prompted. Do not put it +in the command itself: your shell may save it in its history. ## Report a security problem diff --git a/docs/user/guide.md b/docs/user/guide.md index edcef9a9..2aefdf83 100644 --- a/docs/user/guide.md +++ b/docs/user/guide.md @@ -87,24 +87,18 @@ codex32 detects and reports the local Bitcoin Core network. You do not need to change `bitcoin.conf` when using the standard local data directory and RPC port. -Use a trusted computer: one under your exclusive control, not known or suspected -to be compromised, with its operating system, Python environment, terminal, -codex32, `bitcoin-cli`, Bitcoin Core, and relevant configuration trusted for the -operation. Wallet encryption or RPC authentication does not make a compromised -computer safe. An offline trusted computer stays disconnected from every network -before, while, and after it handles private recovery or signing material. Only -codex32 and Bitcoin Core should perform recovery, derivation, wallet -initialization, or signing. The QR tools below transport only public descriptors -or PSBTs. - -Bitcoin Core wallet encryption is strongly recommended. Bitcoin Core owns the -passphrase and its prompts; codex32 never asks for, reads, or forwards it. - -Do not type recovery text on the same line as a command: shell history, terminal -logging, wrappers, or process tooling may retain the command text. Run the -command first, then enter a master seed or shares on the separate `>` line when -prompted. Standard-input redirection also keeps recovery text out of process -arguments, but protect the redirected source separately. +Use a computer you control and whose software you trust. Malware can steal +recovery material even from an encrypted wallet. For more protection, disconnect +from all networks before entering secrets and stay offline until shutdown. +Use codex32 to create or recover backups, and Bitcoin Core to manage your wallet, +review transactions, and sign them. QR codes below carry only public wallet +details or partially signed transactions. + +Bitcoin Core wallet encryption is strongly recommended. Keep its passphrase +safe; codex32 never asks for it. + +Run the command first, then type your seed or shares at the `>` prompt. Never +put recovery text in the command itself: your shell may save that text. This keeps a 48-character string grouped in fours within an 80-column terminal. Later share prompts may show a fixed common header after `>`. Never photograph recovery text or put it in a website, chat, cloud clipboard, or online QR diff --git a/src/codex32/_cli_parser.py b/src/codex32/_cli_parser.py index 12178945..05912fdd 100644 --- a/src/codex32/_cli_parser.py +++ b/src/codex32/_cli_parser.py @@ -86,9 +86,8 @@ def parser(prog: str = "codex32", *, master_seed: bool = False) -> argparse.Argu if master_seed else "Check, correct, recover, and derive shares from codex32 backups." ), - epilog="Never put a secret or share in command arguments or shell command text.\n" - "Enter it when prompted; some commands also accept redirected standard input.\n" - "Protect redirected files; shells and terminals may keep text.", + epilog="Never put a secret or share in a command.\n" + "Enter it when prompted. Some commands also accept piped input.", formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False, ) diff --git a/tests/test_generic_hrp.py b/tests/test_generic_hrp.py index 41c5b2f6..503be279 100644 --- a/tests/test_generic_hrp.py +++ b/tests/test_generic_hrp.py @@ -125,9 +125,8 @@ def test_cli_split_and_unknown_neutral_summary() -> None: " create create or confirm a backup, or split an existing secret\n" " wallet restore a Bitcoin Core wallet\n" " xprv export the root extended private key\n\n" - "Never put a secret or share in command arguments or shell command text.\n" - "Enter it when prompted; some commands also accept redirected standard input.\n" - "Protect redirected files; shells and terminals may keep text.\n" + "Never put a secret or share in a command.\n" + "Enter it when prompted. Some commands also accept piped input.\n" ) for command in ("check", "correct", "secret", "share"): assert command in generic_help and command in ms_help From 974657f4171ad13534a94fa3d065411e87a57596 Mon Sep 17 00:00:00 2001 From: Ben Westgate Date: Sat, 24 Oct 2026 09:41:43 -0500 Subject: [PATCH 5/8] docs: Shorten trusted-computer guidance Keep the trusted-computer definition in the technical model and plain advice in the user documents. Limit the requirement to sensitive work and state the intended-output exception without repeating its rationale. Refs #4, #59. The focused CLI help test and diff checks pass. --- docs/security/model.md | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/docs/security/model.md b/docs/security/model.md index d7be9ab8..02071327 100644 --- a/docs/security/model.md +++ b/docs/security/model.md @@ -31,21 +31,18 @@ fingerprints, and wallet history cannot spend funds but remain privacy-sensitive ## Operator assumptions -A **trusted computer** is under the operator's exclusive control, is not known -or suspected to be compromised, and runs an operating system and other software -the operator trusts for the operation. For codex32 wallet work, that trusted -software includes the Python environment, codex32, the terminal, `bitcoin-cli`, -Bitcoin Core, and their relevant configuration. An offline trusted computer -remains disconnected from every network before, while, and after it handles -private recovery or signing material. Wallet encryption, application -permissions, and RPC authentication do not make a compromised computer trusted. +A **trusted computer** is one the operator controls and has no reason to suspect +is compromised, with trusted software and configuration, including Python, +codex32, the terminal, `bitcoin-cli`, and Bitcoin Core. Wallet encryption cannot +protect secrets from malware. A dedicated offline signer stays disconnected +from every network, including after use. The operator must: - use only Bitcoin Core descriptor wallets to sign with keys derived from a codex32 master seed; -- use only trusted computers as defined above for codex32 operations, wallet - initialization, and signing with Bitcoin Core; +- use a trusted computer for operations involving recovery material, wallet + initialization, or signing with Bitcoin Core; - disconnect every computer used for offline codex32 or signing work from all network paths, including Ethernet, internet, Tor, Wi-Fi, Bluetooth, and cellular; @@ -61,13 +58,10 @@ The operator must: - never put recovery text in command arguments or transfer a master seed, share, xprv, or private descriptor through QR or a network service. -`create`, `secret`, `share`, `correct`, and `xprv` can intentionally display -secret-bearing recovery material because producing or exporting that material is -their purpose. This is distinct from accidental disclosure: unrelated status, -diagnostic, logging, and wallet-integration output must not reveal secrets. -Prompted input and standard-input redirection keep recovery text out of process -arguments, but the operator must also keep the text out of shell command text; -shell history, terminal logging, wrappers, or process tooling may retain it. +`create`, `secret`, `share`, `correct`, and `xprv` intentionally display recovery +material. Unrelated output and diagnostics must not disclose it. Enter recovery +text only when prompted or through stdin; putting it in a shell command can +expose it through history or process arguments. ## Security limitations From 4e3bd9f87411732ad1fadb7231a20f7724dcd811 Mon Sep 17 00:00:00 2001 From: Ben Westgate Date: Tue, 27 Oct 2026 00:05:28 -0500 Subject: [PATCH 6/8] docs: Centralize trusted-computer guidance Define trusted computer once in SECURITY.md and link the model, invariants and user guide to it. Ground encryption and permanent offline-signing advice in Bitcoin Core v32.0 sources, removing the shutdown-only wording and repeated output explanation. No runtime or reportability changes. Checked the complete diff, relative anchors, upstream source links, policy resolution, line widths and whitespace. Application tests were not run for prose-only edits. Refs #4, #59. --- SECURITY.md | 32 ++++++++++++++++++++++---------- docs/security/invariants.md | 12 +++++------- docs/security/model.md | 13 +------------ docs/user/guide.md | 11 ++--------- 4 files changed, 30 insertions(+), 38 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 4d21bd26..d4cad534 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,21 +1,33 @@ # Security -codex32 handles wallet backup and recovery secrets. Use a computer you control -and whose software you trust. Malware can steal secrets even when the wallet is -encrypted. Have the software and recovery plan reviewed before using real funds. -For stronger isolation, keep the computer offline until you shut it down. +codex32 handles wallet backup and recovery secrets. Have the software and +recovery plan reviewed before using real funds. + +## Trusted computer + +A **trusted computer** is one you control, believe is free of malware, and whose +operating system and other software you trust. Use one for backup creation, +recovery, wallet setup, and signing. + +Follow [Bitcoin Core's wallet-encryption guidance][core-wallet]. Encryption +cannot fully protect your bitcoins from malware, as [Core's encryption dialog +warns][core-dialog]. Keep your wallet passphrase safe. + +For stronger isolation, use an offline signing computer that never connects to +any network, as in [Bitcoin Core's offline-signing tutorial][core-offline]. A valid checksum detects many copying mistakes. It does not prove that a backup belongs to your wallet. A correction is only a suggestion; compare it with the physical backup and wallet information kept elsewhere. -codex32 does not intentionally save secrets or put them in command arguments, -logs, or unrelated output. Commands that create or recover backups may display -the recovery text on purpose. Python and the operating system may retain copies -in memory, terminal scrollback, or disk. Tails and shutdown reduce this risk. +codex32 is designed to avoid accidental disclosure. Commands may display recovery +material when that is their purpose. Python and the operating system may retain +copies in memory, terminal scrollback, or disk. Tails and shutdown reduce this +risk but do not guarantee erasure. -Run a command first, then enter your recovery text when prompted. Do not put it -in the command itself: your shell may save it in its history. +[core-wallet]: https://github.com/bitcoin/bitcoin/blob/v32.0/doc/managing-wallets.md#12-encrypting-the-wallet +[core-dialog]: https://github.com/bitcoin/bitcoin/blob/v32.0/src/qt/askpassphrasedialog.cpp +[core-offline]: https://github.com/bitcoin/bitcoin/blob/v32.0/doc/offline-signing-tutorial.md ## Report a security problem diff --git a/docs/security/invariants.md b/docs/security/invariants.md index 51aa9c34..6ff1f60f 100644 --- a/docs/security/invariants.md +++ b/docs/security/invariants.md @@ -32,11 +32,9 @@ and evidence. admitted classes ranked equal to or better than the candidate, independently of execution order. 6. Secrets stay out of command arguments, logs, unrelated output, and public - transfers. Commands whose purpose is to create, recover, derive, correct, or - explicitly export recovery material may intentionally display that material - to the operator. During wallet setup, codex32 transfers the master xprv only - through child stdin. Private descriptors exist only in Python memory and child - stdin. + transfers. Only commands intended to produce recovery material may display it. + During wallet setup, codex32 transfers the master xprv only through child stdin. + Private descriptors exist only in Python memory and child stdin. 7. Bitcoin Core chains are discovered before entropy or recovery input. The operator confirms an eligible descriptor wallet by exact name. 8. Wallet state is revalidated before handing Core the master key. Core must @@ -45,8 +43,8 @@ and evidence. and verified on every exit path. 10. External text, Core output, public wallet data, and PSBTs are untrusted. 11. Only Bitcoin Core descriptor wallets sign with codex32-derived keys. - Sensitive operations use only codex32 or Core on a trusted computer as - defined by the security model. + Sensitive operations use only codex32 or Core on a + [trusted computer](../../SECURITY.md#trusted-computer). 12. Offline hosts disable every network path, including Ethernet, internet, Tor, Wi-Fi, Bluetooth, and cellular. Online Core nodes synchronize before their balances or history are trusted. diff --git a/docs/security/model.md b/docs/security/model.md index 02071327..e717ee29 100644 --- a/docs/security/model.md +++ b/docs/security/model.md @@ -31,17 +31,11 @@ fingerprints, and wallet history cannot spend funds but remain privacy-sensitive ## Operator assumptions -A **trusted computer** is one the operator controls and has no reason to suspect -is compromised, with trusted software and configuration, including Python, -codex32, the terminal, `bitcoin-cli`, and Bitcoin Core. Wallet encryption cannot -protect secrets from malware. A dedicated offline signer stays disconnected -from every network, including after use. - The operator must: - use only Bitcoin Core descriptor wallets to sign with keys derived from a codex32 master seed; -- use a trusted computer for operations involving recovery material, wallet +- use a [trusted computer](../../SECURITY.md#trusted-computer) for recovery material, wallet initialization, or signing with Bitcoin Core; - disconnect every computer used for offline codex32 or signing work from all network paths, including Ethernet, internet, Tor, Wi-Fi, Bluetooth, and @@ -58,11 +52,6 @@ The operator must: - never put recovery text in command arguments or transfer a master seed, share, xprv, or private descriptor through QR or a network service. -`create`, `secret`, `share`, `correct`, and `xprv` intentionally display recovery -material. Unrelated output and diagnostics must not disclose it. Enter recovery -text only when prompted or through stdin; putting it in a shell command can -expose it through history or process arguments. - ## Security limitations - Python cannot guarantee zeroization, constant-time execution, locked memory, diff --git a/docs/user/guide.md b/docs/user/guide.md index 2aefdf83..c0b57605 100644 --- a/docs/user/guide.md +++ b/docs/user/guide.md @@ -87,15 +87,8 @@ codex32 detects and reports the local Bitcoin Core network. You do not need to change `bitcoin.conf` when using the standard local data directory and RPC port. -Use a computer you control and whose software you trust. Malware can steal -recovery material even from an encrypted wallet. For more protection, disconnect -from all networks before entering secrets and stay offline until shutdown. -Use codex32 to create or recover backups, and Bitcoin Core to manage your wallet, -review transactions, and sign them. QR codes below carry only public wallet -details or partially signed transactions. - -Bitcoin Core wallet encryption is strongly recommended. Keep its passphrase -safe; codex32 never asks for it. +Use a [trusted computer](../../SECURITY.md#trusted-computer) for backup, +recovery, and signing. Follow the wallet-encryption guidance there. Run the command first, then type your seed or shares at the `>` prompt. Never put recovery text in the command itself: your shell may save that text. From e2a95f10737f7cf9a63ab05a08b1d3fdacc5bd24 Mon Sep 17 00:00:00 2001 From: Ben Westgate Date: Tue, 27 Oct 2026 00:28:55 -0500 Subject: [PATCH 7/8] docs: Address security guidance review Require exclusive control, centralize network requirements, and make clear that every sensitive operation uses the trusted computer. Restore the guide's explicit encryption recommendation and the original Python memory limitation. Shorten the malware and intentional-output wording. Timestamped rescans still capture a private descriptor from Core and re-import it over stdin; describe that path rather than removing its secret-channel requirement. Preserve invariant numbering with a link. Checked the exact rescan call path, documentation diff, anchors, line widths, whitespace and policy resolution. No application tests were run for prose-only changes. Refs #4, #59. --- SECURITY.md | 27 +++++++++++++++++---------- docs/security/invariants.md | 10 ++++------ docs/security/model.md | 10 +++------- docs/user/guide.md | 5 ++++- 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index d4cad534..d2e6b2d2 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -5,25 +5,32 @@ recovery plan reviewed before using real funds. ## Trusted computer -A **trusted computer** is one you control, believe is free of malware, and whose -operating system and other software you trust. Use one for backup creation, -recovery, wallet setup, and signing. +A **trusted computer** is under your exclusive control, is believed free of +malware, and runs an operating system and other software you trust. Use one for +backup creation, recovery, wallet setup, and signing. Follow [Bitcoin Core's wallet-encryption guidance][core-wallet]. Encryption -cannot fully protect your bitcoins from malware, as [Core's encryption dialog -warns][core-dialog]. Keep your wallet passphrase safe. +[cannot fully protect your bitcoins from malware][core-dialog]. Keep your +wallet passphrase safe. For stronger isolation, use an offline signing computer that never connects to -any network, as in [Bitcoin Core's offline-signing tutorial][core-offline]. +any network, including Ethernet, internet, Tor, Wi-Fi, Bluetooth, or cellular, +as in [Bitcoin Core's offline-signing tutorial][core-offline]. Online Core nodes +must synchronize before their balances or history are trusted. A valid checksum detects many copying mistakes. It does not prove that a backup belongs to your wallet. A correction is only a suggestion; compare it with the physical backup and wallet information kept elsewhere. -codex32 is designed to avoid accidental disclosure. Commands may display recovery -material when that is their purpose. Python and the operating system may retain -copies in memory, terminal scrollback, or disk. Tails and shutdown reduce this -risk but do not guarantee erasure. +codex32 is designed to avoid accidental disclosure; commands display recovery +material only when that is their purpose. + +Python, your terminal, and your operating system may retain secret text in +memory or scrollback. codex32 does not intentionally save secrets and keeps +them out of command arguments and normal machine output, but it cannot +guarantee that every copy is erased from swap, hibernation data, or crash +dumps. Using Tails and shutting down when finished helps mitigate this Python +limitation. [core-wallet]: https://github.com/bitcoin/bitcoin/blob/v32.0/doc/managing-wallets.md#12-encrypting-the-wallet [core-dialog]: https://github.com/bitcoin/bitcoin/blob/v32.0/src/qt/askpassphrasedialog.cpp diff --git a/docs/security/invariants.md b/docs/security/invariants.md index 6ff1f60f..24fde0a9 100644 --- a/docs/security/invariants.md +++ b/docs/security/invariants.md @@ -34,7 +34,8 @@ and evidence. 6. Secrets stay out of command arguments, logs, unrelated output, and public transfers. Only commands intended to produce recovery material may display it. During wallet setup, codex32 transfers the master xprv only through child stdin. - Private descriptors exist only in Python memory and child stdin. + Timestamped rescans capture Core's private descriptor output and return it + through child stdin, never command arguments or operator output. 7. Bitcoin Core chains are discovered before entropy or recovery input. The operator confirms an eligible descriptor wallet by exact name. 8. Wallet state is revalidated before handing Core the master key. Core must @@ -43,10 +44,7 @@ and evidence. and verified on every exit path. 10. External text, Core output, public wallet data, and PSBTs are untrusted. 11. Only Bitcoin Core descriptor wallets sign with codex32-derived keys. - Sensitive operations use only codex32 or Core on a - [trusted computer](../../SECURITY.md#trusted-computer). -12. Offline hosts disable every network path, including Ethernet, internet, - Tor, Wi-Fi, Bluetooth, and cellular. Online Core nodes synchronize before - their balances or history are trusted. +12. Computer and network use follows the requirements in + [SECURITY.md](../../SECURITY.md#trusted-computer). Changes require matching model, tests, and security-review evidence. diff --git a/docs/security/model.md b/docs/security/model.md index e717ee29..4b4ca22d 100644 --- a/docs/security/model.md +++ b/docs/security/model.md @@ -35,13 +35,9 @@ The operator must: - use only Bitcoin Core descriptor wallets to sign with keys derived from a codex32 master seed; -- use a [trusted computer](../../SECURITY.md#trusted-computer) for recovery material, wallet - initialization, or signing with Bitcoin Core; -- disconnect every computer used for offline codex32 or signing work from all - network paths, including Ethernet, internet, Tor, Wi-Fi, Bluetooth, and - cellular; -- synchronize Bitcoin Core on the networked computer before trusting its - balances or history; +- follow the [computer requirements](../../SECURITY.md#trusted-computer) for all + operations involving recovery material, including wallet initialization and + signing with Bitcoin Core; - protect recovery cards and store shared cards in different trusted places; - confirm every newly recorded secret or share; - keep wallet records separate from shares, type the master fingerprint from diff --git a/docs/user/guide.md b/docs/user/guide.md index c0b57605..a4edbb8a 100644 --- a/docs/user/guide.md +++ b/docs/user/guide.md @@ -88,7 +88,10 @@ change `bitcoin.conf` when using the standard local data directory and RPC port. Use a [trusted computer](../../SECURITY.md#trusted-computer) for backup, -recovery, and signing. Follow the wallet-encryption guidance there. +recovery, and signing. + +Bitcoin Core wallet encryption is strongly recommended. Bitcoin Core owns the +passphrase and its prompts; codex32 never asks for, reads, or forwards it. Run the command first, then type your seed or shares at the `>` prompt. Never put recovery text in the command itself: your shell may save that text. From 0d4ac621b6178054daf240b4bf976a042931195f Mon Sep 17 00:00:00 2001 From: Ben Westgate Date: Tue, 27 Oct 2026 00:40:04 -0500 Subject: [PATCH 8/8] docs: Use direct trusted-computer wording Apply the reviewer's active wording while preserving exclusive control and trust in the operating system and other software. Meaning unchanged. Checked the two-line prose diff and line widths; no runtime tests needed. Refs #59. --- SECURITY.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index d2e6b2d2..9c137c78 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -5,8 +5,8 @@ recovery plan reviewed before using real funds. ## Trusted computer -A **trusted computer** is under your exclusive control, is believed free of -malware, and runs an operating system and other software you trust. Use one for +A **trusted computer** is one you exclusively control, believe is free of +malware, and whose operating system and other software you trust. Use one for backup creation, recovery, wallet setup, and signing. Follow [Bitcoin Core's wallet-encryption guidance][core-wallet]. Encryption