match the amounts in rbf insufficient fee broadcast errors without backtracking
What changed, and why it matters
This commit tightens two text-parsing regular expressions in Sparrow Wallet that read error messages returned by Bitcoin nodes when a Replace-By-Fee (RBF) transaction is rejected for an insufficient fee. The change prevents the regex from backtracking into earlier digits in the error string, which could previously cause the wallet to extract the wrong fee amounts and display misleading guidance to the user. It is a robustness fix for user-facing diagnostics, not a cryptographic or network vulnerability.
Treat as a low-severity hardening fix. Review whether the regexes are still aligned with current Bitcoin Core error-message formats and consider adding unit tests for parsing edge cases. No urgent security response is indicated.
Security signals we found
Regular expression hardening against backtracking and greedy mis-match
Parsing of externally supplied error strings from Bitcoin network peers
User-facing fee guidance depends on parsed values
Evidence from the diff
HeadersController.java contains regexes that parse Bitcoin Core-style P2P/RBF rejection messages to extract the actual and required fee (or fee rate). The old patterns used greedy quantifiers (\d+.?\d) without anchors, so on certain error strings they could match earlier numeric substrings instead of the intended final values. The new patterns add possessive quantifiers (\d++.?+\d+) and a negative lookbehind for digits/decimal points (?<![\d.]) so the match starts at the intended number and does not backtrack. This improves parsing accuracy when the node returns multi-number messages, reducing the chance that Sparrow misreports why a replacement was rejected.
Changed components
src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.javaRBF insufficient-fee error parsingWallet transaction broadcast feedback UIInspect captured patch +2 / −2
### src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java
@@ -84,8 +84,8 @@ public class HeadersController extends TransactionFormController implements Init
public static final String MIN_LOCKTIME_DATE = "1985-11-05T00:53:20Z";
private static final Pattern MIN_MEMPOOL_FEE = Pattern.compile("the transaction was rejected by network rules.*mempool min fee not met, (\\d+) < (\\d+).*", Pattern.DOTALL | Pattern.MULTILINE);
- private static final Pattern RBF_INSUFFICIENT_FEE = Pattern.compile("insufficient fee, rejecting replacement.*?(\\d+\\.?\\d*) < (\\d+\\.?\\d*)");
- private static final Pattern RBF_INSUFFICIENT_FEE_RATE = Pattern.compile("insufficient fee, rejecting replacement.*new feerate (\\d+\\.?\\d*)[^\\d]*(\\d+\\.?\\d*)[^\\d]*");
+ private static final Pattern RBF_INSUFFICIENT_FEE = Pattern.compile("insufficient fee, rejecting replacement.*?(?<![\\d.])(\\d++\\.?+\\d*+) < (\\d++\\.?+\\d*+)");
+ private static final Pattern RBF_INSUFFICIENT_FEE_RATE = Pattern.compile("insufficient fee, rejecting replacement.*new feerate (\\d++\\.?+\\d*+)[^\\d]*+(\\d++\\.?+\\d*+)[^\\d]*+");
private static final double FEE_MULTIPLE_LIMIT = 100d;
Why this scored 16/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.