Subject: [bitcoin-dev] Parameters in BIP21 URIs

From: kiminuo <[email-masked]>
Date: Fri, 08 Sep 2023 14:36:16 +0000

[Formatted version of this post is here: https://gist.github.com/kiminuo/cc2f19a4c5319e439fc7be8cbe5a39f9]

Hi all,

BIP 21 [https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki] defines a URI scheme for making Bitcoin payments and the purpose of the URI scheme is to enable users to easily make payments by simply clicking links on webpages or scanning QR Codes. An example of a BIP21 URI is:

bitcoin:bc1qd4fxq8y8c7qh76gfnvl7amuhag3z27uw0w9f8p?amount=0.004&label=Kiminuo&message=Donation

Now to make it easier, these URIs are typically clickable. Bitcoin wallets register the "bitcoin" URI scheme so that a BIP21 URI is parsed and data are pre-filled in a form to send your bitcoin to a recipient. Notably, wallets do not send your bitcoin once you click a BIP21 URI, there is still a confirmation step that requires user's attention. Very similar experience is with a QR code that encodes a BIP21 URI where one just scans a QR code and data is, again, pre-filled in a wallet's UI for your convenience.

While working on Wasabi's BIP21 implementation I noticed that based on the BIP21 grammar [https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki#abnf-grammar], it is actually allowed to specify URI parameters multiple times. This means that the following URI is actually valid:

bitcoin:bc1qd4fxq8y8c7qh76gfnvl7amuhag3z27uw0w9f8p?amount=0.004&label=Kiminuo&message=Donation&amount=1.004 (note that the 'amount' parameter is specified twice)

Bitcoin Core implements "the last value wins" behavior[^3] so amount=1.004 will be taken into account and not "amount=0.004"[^4]. However, in general, the fact that the same parameter can be specified multiple times can lead to a confusion for users and developers[^1][^2]. In the worst case, it might be exploited by some social engineering attempts by attempting to craft a 'clever' BIP21 URI and exploting behavior of a particular wallet software. For the record, I'm not aware that it actually happens, so this is rather a concern.

The main question of this post is: Is it useful to allow specifying BIP21 parameters multiple times or is it rather harmful?

Regards,
K.

[^1]: https://github.com/JoinMarket-Org/joinmarket-clientserver/pull/1510
[^2]: https://github.com/MetacoSA/NBitcoin/blob/93ef4532b9f2ea52b2c910266eeb6684f3bd25de/NBitcoin/Payment/BitcoinUrlBuilder.cs#L74-L78
[^3]: I added a test to that effect in https://github.com/bitcoin/bitcoin/pull/27928/files, see https://github.com/bitcoin/bitcoin/blob/83719146047947e588aa0c7b5eee02f44884553d/src/qt/test/uritests.cpp#L68-L73.[^4]: You can test your wallet's behavior by scanning the last image here https://github.com/zkSNACKs/WalletWasabi/pull/10578#issue-1687564404 (or directly https://user-images.githubusercontent.com/58662979/265389405-16893ce8-7c19-4262-bb60-5fd711336685.png).