Writing · September 2026
The name became the command.
Every shop has a jig nobody thinks about anymore. Somebody built it years ago to make the same cut the same way, and it has made that cut a thousand times since. Then one day somebody tidies up the bench, rebuilds the jig out of nicer material, and it looks identical. It isn't. The stop moved an eighth of an inch, and nobody measures a jig that has always been right.
Bitcoin Core rebuilt a jig in 2022. This week we found out the stop moved.
What happened
On September 14, Bitcoin Core tagged its first 32.0 release candidate. Most of the draft release notes cover the kind of work node operators like. One sentence in the wallet section is a different kind: on non-Windows systems, "an authenticated RPC caller allowed to create wallets could execute arbitrary commands as the node process account when -walletnotify was configured, by crafting a wallet name with regex replacement characters."
-walletnotify is an old operator feature. You give the node a shell command, and it runs that command whenever a wallet transaction changes. It's the hook you use to learn a deposit landed. The command can include %w, which the node replaces with the wallet's name, and because whoever creates a wallet picks its name, the node shell-escapes that name first.
The escaping was fine. The substitution wasn't.
The fix, opened by contributor l0rinc on August 20 and merged September 2, traces the bug to a 2022 refactor whose whole purpose was dropping a Boost dependency. Good hygiene. It swapped a plain find-and-replace for C++'s std::regex_replace(). That function doesn't treat replacement text as text. A sequence like $' is an instruction. A wallet name carrying one could break the quoting around itself, and with a suitable command template, the PR says, run additional shell commands as the node's own account. The PR says the bug affects version 24.0 onward and credits its discovery to "the Red Team."
Nobody wrote a bad line of security code. Somebody removed a dependency, and a name became a command.
Where the fix actually is
Here's what the release notes don't say, and the reason I'm writing.
CoinDesk reported that 32.0 final is expected around October 10. Until then, the fix exists in a release candidate and nowhere else. As of September 17, src/util/string.cpp on the 31.x, 30.x and 29.x branches still calls regex_replace. The latest stable releases, 31.1, 30.3 and 29.4, all shipped in July, before the fix was merged. The backport batches merged on September 10 for 31.x and 30.x carry a macOS build fix and nothing else. On August 31 a reviewer wrote in the fix's thread that it "should probably have release notes, and be backported." As of today, it hasn't been.
Blockchain AI News laid out the backport gap today. Don't take that on faith, or this piece on faith either. Every link above goes to the code.
Who this is for, and who it isn't
The conditions are narrow, and I don't want to oversell them. An attacker needs authenticated RPC access with permission to create wallets, plus a transaction sent to the wallet they name. The node has to run -walletnotify, on something other than Windows. The PR says it is not reachable over the peer-to-peer network or by anyone without credentials. Nobody has reported it being exploited.
If you run a node at home with no walletnotify line, this bug doesn't reach you.
But "authenticated" is not the same word as "trusted." Think about where RPC credentials end up once a node has been running a while: a dashboard, a script, a payment tool, a helper app somebody recommended. Unless you restricted them, every one of those can call createwallet. On a node running walletnotify, until 32.0, every one of them could also hold the right to run commands as your node.
The ten-minute check
Open your bitcoin.conf and search for walletnotify. If it isn't there, you're done.
If it is:
- Look for
%win the command. In Bitcoin Core's code, the wallet name only enters the command through%w. If your script can live without the name until 32.0 ships, take it out. - List everything that holds your RPC credentials. Not what you meant to give them to. What actually has them.
- Restrict who can call
createwallet. Bitcoin Core's-rpcwhitelistoption lets you set, per RPC user, which calls that user may make. A dashboard that reads balances has no business creating wallets. - Plan the 32.0 upgrade for after the final release, not the release candidate, unless testing release candidates is already part of how you run things.
The lesson I keep coming back to is the one from the jig. The cut you stopped measuring is the one that goes wrong, because a cleanup looks exactly like the thing it replaced. Nobody here was careless. That is what makes it worth taking seriously.
Verify everything — including the settings you wrote years ago and forgot.
— Jon Tetreault, September 2026. The habits, tools, and checks behind this piece are what I teach in Crypto Security Mastery.