Key takeaways
- bitcoinjs-lib disclosed two high-severity PSBT fee-accounting bugs on 26 October 2026 - GHSA-4mfv-5394-26c7 and GHSA-h52v-8xwg-7j95 - fixed in 5.2.2, 6.1.9 and 7.0.4.
- In one demonstration the true fee was 900,000,000 satoshis - 9 BTC - while the library reported 200. In another, a 91,000-satoshi fee was shown as 1,000.
- A Bitcoin fee is not a field in a transaction. It is the leftover: inputs minus outputs. Misread an input's value and the leftover is wrong, and the leftover goes to a miner.
- Six High advisories were published that day, not two. The other four include proof-of-work verification accepting invalid compact targets and merkle node duplication validating a forged transaction list.
- No losses are confirmed and no exploitation is reported. The fee risk applies to apps that accept untrusted PSBTs and rely on the library's fee calculation.
On 26 October, the maintainers of bitcoinjs-lib published a security advisory with a demonstration in it. The transaction's true fee was 900,000,000 satoshis. The library reported the fee as 200.
Nine hundred million satoshis is nine bitcoin. The figure is arresting enough that most coverage stopped there, which is a shame, because the interesting part is not the size of the error. It is which number was wrong.
A fee is not a field
Here is the thing most people never have cause to learn. A Bitcoin transaction contains no fee. There is no field for it. Nowhere in the serialised transaction does a number appear saying what the miner gets.
The fee is the residue: the sum of the inputs minus the sum of the outputs. Whatever you put in and did not explicitly send somewhere is the fee, by definition, automatically.
So when your wallet shows you a fee, it is not reporting a parameter it set. It is doing arithmetic on your behalf and telling you the remainder. And that arithmetic needs to know, exactly, what every input is worth.
This is also why the fee is the one number in a transaction that nobody independently verifies. You check the recipient address, often character by character. You check the amount, because you chose it. The fee you accept, because confirming it would mean knowing the value of every output you are spending from and doing the subtraction yourself. Practically nobody does. It is the field we have delegated completely.
What the two bugs actually did
Both concern PSBTs - partially signed Bitcoin transactions, the format wallets and hardware devices use to pass a half-built transaction between each other.
GHSA-4mfv-5394-26c7, "Conflicting PSBT UTXO records can understate transaction fees": signing used the real previous transaction, while the fee calculation used a smaller, conflicting value from a witnessUtxo record. The two halves of the code disagreed about what the same input was worth. The signature still verified, and the transaction came out without triggering the default fee-rate warning.
GHSA-h52v-8xwg-7j95, "Finalized PSBT inputs without UTXO records are counted as zero in fee calculations": if a finalised input's PSBT carried neither a witnessUtxo nor a nonWitnessUtxo record, the input was treated as worth nothing. In the published example, inputs of 10,000 and 90,000 satoshis funded outputs totalling 9,000. The real fee was 91,000 satoshis. The calculator said 1,000.
Notice the shape of both. Neither bug sends money to an attacker. Both make the app's arithmetic disagree with the chain's arithmetic - and the chain's version is the one that settles. The excess simply becomes the miner's fee, which is to say it is gone, paid to someone with no obligation and often no practical means to return it.
Fixes are in 5.2.2, 6.1.9 and 7.0.4, across three release lines. For anything that cannot upgrade, the advised mitigation is to verify each input's referenced output value and reject conflicting records.
The four advisories nobody mentioned
This is what reading the advisory page gets you that reading the coverage does not.
Six advisories were published that day, all rated High, all by the same maintainer. The fee pair got the attention because it came with a dramatic number. The other four:
Proof-of-work verification accepts invalid compact targets. Code that checks whether a block meets its difficulty target can be satisfied by a target it should have rejected.
Undetected merkle node duplication in block root computation validates a forged transaction list. This is a recognisable class - duplicating nodes in a merkle tree so a different transaction list produces the same root. If your code computes a merkle root to decide whether a transaction is really in a block, it can be shown a list that is not the real one.
Two denial-of-service issues, where block parsing and repeated integer reads copy whole buffers per transaction.
Judged by character rather than headline, the middle two are the ones I would worry about more. Overpaying a fee costs money once. Being persuaded that a forged transaction list is valid undermines the thing verification exists to do.
The honest qualifier: that only matters if an application uses this library for block verification at all, and most do not - most wallets ask a server and trust the answer. But the apps that do verify are precisely the ones whose users believe they are not trusting anybody, which makes it the worst possible place for a verification bug to sit quietly.
Why you cannot check this one yourself
Two days ago I wrote about a BTCPay fix that was merged but not yet released, and the practical advice there was to compare your version string against the repository's release history. You could do that. It took seconds.
That advice does not transfer here, and it is worth being clear about why. bitcoinjs-lib is a dependency. It sits inside applications you installed, bundled at build time. There is no setting that tells you which version of it your wallet ships, no footer with a string in it, and no realistic way for a non-developer to find out.
So the gap between "fixed upstream" and "fixed in the thing you are using" is not just invisible here - it is unmeasurable from the outside. Your only lever is the application's own release notes, and whether its developers mention dependency updates at all.
What is not established
Three limits, because the coverage of this has been looser than the advisories themselves.
No losses are confirmed. The published cases demonstrate miscalculation, not theft and not exploitation in the wild. A real loss requires a valid transaction to be broadcast and accepted.
The exposure is conditional. The fee risk applies to applications that accept PSBTs from untrusted sources and rely on the library's fee calculation or its fee-rate check. An app that builds its own transactions from its own inputs is in a different position.
Do not conflate this with the Electrum story. In the same week, a separate flaw was disclosed in which malicious servers could redirect funds when users tried to fee-bump a payment, and there at least one theft is confirmed. Different software, different mechanism, genuinely worse outcome. Several write-ups have blurred the two.
The habit worth taking from it
If you move bitcoin manually, the practical check is unglamorous: before you confirm, look at what you are spending and what is arriving, and satisfy yourself that the difference is roughly the fee the screen claims. Not to second-guess your wallet. To notice the one case in a thousand where the subtraction does not come out.
And if you build on this library, upgrade, and read all six advisories rather than the two with the memorable number in them.
The general lesson is smaller than "Bitcoin is unsafe" and more useful. Derived numbers are more dangerous than stated ones, because nobody audits a value that was never typed in. The fee was never typed in by anyone. It is what fell out of the sum - and a mistake in a sum that nobody checks is paid, silently, to whoever happens to be mining.
I verified the advisory list and titles against the repository's own security page; the demonstration figures and patched versions come from the advisories as reported, not from testing I have done. None of this is security advice for your particular setup, and it is not investment advice either.
Frequently asked questions
What exactly went wrong in bitcoinjs-lib?
Two high-severity PSBT fee-accounting bugs. In GHSA-4mfv-5394-26c7, signing used the real previous transaction while the fee calculation used a smaller conflicting witnessUtxo value. In GHSA-h52v-8xwg-7j95, a finalised input with neither a witnessUtxo nor a nonWitnessUtxo record was counted as worth zero. Both cause the reported fee to be lower than the fee actually paid.
Why can a wallet get the fee wrong at all?
Because a Bitcoin transaction has no fee field. The fee is the residue - total inputs minus total outputs - so the wallet must know the exact value of every input to tell you what the fee is. If it misreads an input's value, the figure it shows you is wrong while the transaction still pays the real difference.
Which versions are fixed?
5.2.2, 6.1.9 and 7.0.4, across three release lines. Applications that cannot upgrade are advised to verify each input's referenced output value and reject conflicting records.
Has anyone actually lost money?
No losses are confirmed and no exploitation in the wild has been reported. The published examples demonstrate miscalculation. A loss would require a valid transaction to be broadcast and accepted, after which the excess is simply a miner fee.
Were there other advisories the same day?
Yes - six in total, all rated High. Besides the two fee bugs they cover proof-of-work verification accepting invalid compact targets, undetected merkle node duplication that validates a forged transaction list, and two denial-of-service issues involving buffer copying. The verification pair is arguably more serious in character, though it only matters for applications that use the library for block verification.
How do I tell whether my wallet is affected?
Usually you cannot, and that is the awkward part. bitcoinjs-lib is bundled inside applications at build time, so there is no version string to inspect the way there is for self-hosted server software. Your only real source is the application's own release notes and whether its developers mention dependency updates.
Sources
Every figure and quote above traces to one of these. Checked on publication day.
- github.com — bitcoinjs-lib security advisories - GitHub
- tokenpost.com — bitcoinjs-lib Fixes Two PSBT Bugs That Could Hide High Bitcoin Fees - TokenPost
- cryptoslate.com — Bitcoin apps risk massive fee drain, and 2 library bugs are blamed - CryptoSlate
- thecurrencyanalytics.com — Bitcoinjs-lib patches fee accounting bugs - The Currency Analytics
- coindesk.com — Bitcoin wallet bug let rogue servers steal funds when users tried to speed up payments - CoinDesk
- kucoin.com — Bitcoinjs-lib Patches 2 Bugs That Could Cause Fee Underestimation - KuCoin News
Deepmoni Das, Editor
I read the primary filings, exchange notices and post-mortems behind each story and write up what they actually say — with every source linked so you can check me. I am not a trader and I do not hold positions in anything covered here. Research and drafting are AI-assisted; the sourcing, the edits and the mistakes are mine.
Not financial advice. Crypto assets are volatile and unregulated in many jurisdictions. In India, gains are taxed at 30% with 1% TDS on transfers. Do your own research and never invest money you cannot afford to lose.
Editorial note: Crypto Shakti uses an AI-assisted research and drafting workflow. Every article is grounded in the linked primary sources and live market data captured at publication time.
