Document signing behavior with sighash flags, and external inputs
What changed, and why it matters
This commit only adds documentation. It explains how the Ledger Bitcoin app handles unusual signing options (non-default sighash flags and transactions with external inputs) and what warnings users see. There are no code changes, so it does not introduce, fix, or change any security behavior by itself.
No action required; review the documentation for accuracy if desired, but the commit itself carries no deployable security risk or fix.
Security signals we found
documentation-only change
no executable code modified
describes existing security controls (sighash opt-in, external-input warnings)
Evidence from the diff
The diff is a pure documentation update to doc/features.md and doc/integration.md. It describes existing app behavior: default sighash signing, opt-in for non-default sighash types, error codes returned (SW_SECURITY_STATUS_NOT_SATISFIED / 0x000d and SW_NOT_SUPPORTED / 0x0008), the trusted-screen review levels, and warnings for external inputs. No source code, build scripts, tests, or configuration were modified.
Changed components
doc/features.mddoc/integration.mdInspect captured patch +94 / −0
diff --git a/doc/features.md b/doc/features.md
index d03e1d5..e3b1a3b 100644
--- a/doc/features.md
+++ b/doc/features.md
@@ -73,6 +73,39 @@ Taproot policies may use `musig()` key expressions to aggregate several keys int
single on-chain key, following [BIP-0327](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki).
The signing-flow details are covered in [musig.md](musig.md).
+## Advanced signing behaviors
+
+### Sighash flags
+
+The app normally signs its internal inputs with the default sighash type (`SIGHASH_ALL`, or
+`SIGHASH_DEFAULT` for taproot), committing to the whole transaction. Non-default sighash types
+(`SIGHASH_NONE`, `SIGHASH_SINGLE`, and the `SIGHASH_ANYONECANPAY` variants) on inputs the app
+would sign are an advanced use case and are **rejected unless the user first enables them** through
+the *Sighash types* application setting.
+When enabled, each such transaction is still confirmed with a warning. See [integration.md](integration.md#sighash-flags)
+for the setting, the error returned, and the client-side impact (none beyond the PSBT).
+
+### External inputs
+
+Any input of the transaction that is not recognized as belonging to the account the transaction
+is spending from is considered *external* by the application.
+
+The application *cannot* prove with certainty that such inputs are actually external, since
+malicious software wallets might (for example) not reveal the necessary BIP-32 derivations
+in the PSBT.
+
+While the application only signs for the inputs that are proven as internal to the wallet policy
+involved in the spend, certain attacks remain possible where a user is tricked into spending more
+than expected by approving multiple signing requests. Therefore, the application shows a
+**warning** when attempting to sign such transactions. Users **must not approve** such
+transactions unless they fully understand the warning and its consequences, and were expecting it.
+
+For transactions with external inputs, the following additional information is shown:
+- the total amount of external inputs, when it can be reliably determined
+ (see [integration.md](integration.md#external-inputs));
+- the net amount spent from (or received into) the account involved in the transaction,
+ *assuming that the external inputs are indeed external*.
+
## Networks
The app is built per network: the mainnet build is named **Bitcoin**, and the testnet
diff --git a/doc/integration.md b/doc/integration.md
index 6c2d324..0f5551b 100644
--- a/doc/integration.md
+++ b/doc/integration.md
@@ -132,6 +132,67 @@ signature may be returned for that input.
The host is responsible for placing the returned signatures into the PSBT, **finalizing** it,
**extracting** the signed transaction and (possibly) broadcasting it to the network.
+### Sighash flags
+
+By default, the app only signs PSBTs whose internal inputs use the *default* sighash type —
+`SIGHASH_ALL`, or `SIGHASH_DEFAULT` for taproot inputs — so the signature commits to the entire
+transaction. This is what virtually every wallet uses, and it lets the device show full,
+trustworthy details of what is being signed.
+
+The app can also sign with **non-default sighash types** (`SIGHASH_NONE`, `SIGHASH_SINGLE`, and
+any of the `SIGHASH_ANYONECANPAY` combinations), which are needed by certain advanced protocols.
+Because these signatures leave part of the transaction free to change after signing, they are
+**disabled by default**: if an input the app would sign carries a non-default sighash, the PSBT is
+rejected with
+`SW_SECURITY_STATUS_NOT_SATISFIED` (error code `0x000d`, `EC_SIGN_PSBT_NONDEFAULT_SIGHASH_NOT_ALLOWED`),
+and the device briefly shows a notice explaining that the feature is turned off.
+
+For `SIGHASH_SINGLE`, each signed input must have a corresponding output at the same index. If a
+signed input's index is greater than or equal to the number of outputs, the app rejects the PSBT
+with `SW_NOT_SUPPORTED` (error code `0x0008`, `EC_SIGN_PSBT_UNALLOWED_SIGHASH_SINGLE`).
+
+To use them, the user must first opt in through the application settings. Once enabled, signing
+with a non-default sighash is allowed, but still *always* requires explicit user confirmation,
+after a warning and a clear description of the signing rule in use.
+
+### What the device shows when signing
+
+The trusted-screen review adapts to *what the signatures actually commit to*, so the amounts the
+user approves are always meaningful. Depending on the sighash flags of the signed inputs, one of
+three levels of detail is shown:
+
+- **Full details** — used for the default sighash (`SIGHASH_ALL` / `SIGHASH_DEFAULT`) on every
+ signed input. The review lists each external output with its amount and destination, plus the fee.
+ (If the transaction also has external inputs, a couple of extra rows are added; see
+ [External inputs](#external-inputs) below.)
+- **Net amount only** — used for a uniform non-default sighash that still commits to a certain net
+ spend or net receive. The exact fee cannot be known, so in addition to the output list, the device
+ shows the amount spent from (or received into) the account involved in the transaction being signed.
+ The fee is displayed as **Not available**.
+- **Amounts unavailable** — used when nothing coherent can be shown: the signed inputs use different
+ (*mixed*) sighash flags, or a sighash that does not even fix the set of outputs (`NONE`, or
+ `SINGLE` with more than one output, and their `ANYONECANPAY` variants). The device then shows only
+ a notice, and the user merely confirms that they expected and trust the transaction. This is
+ inherently dangerous.
+
+For any non-default sighash, a **Signing rule** row additionally names the effective flag (for
+example `SINGLE`, `ACP | ALL`, or `Mixed`).
+
+### External inputs
+
+An *external input* is an input that the app cannot verify as belonging to the signing wallet
+policy. The app always **warns** about external inputs and, so the user can gauge the transaction's
+real effect, additionally shows:
+
+- the account's net **You spend** / **You receive** amount, since with external inputs the outputs
+ and fee alone can be misleading (the transaction may even be a net *receive*);
+- the **total amount of the external inputs** — unless signing with `SIGHASH_ANYONECANPAY`, which
+ would make that quantity meaningless.
+
+Both figures assume the external inputs indeed do not belong to the account used for signing the
+transaction, which is not something that the app can verify for sure; see
+[features.md](features.md#external-inputs) for why that assumption, and the warning, matter.
+
### Transactions with Wallet Policies using MuSig2
For policies that use `musig()` key expressions, signing is a two-round protocol: the first round
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.