Passphrase Prompt - #63
Conversation
| return null; | ||
| } | ||
|
|
||
| Future<void> _showBottomSheet(final BuildContext context) async { |
There was a problem hiding this comment.
Security audit finding — MEDIUM
Passphrase bottom-sheet Confirm is unguarded and the sheet is never dismissed — double-fire (or a stale re-tap) silently overwrites the wallet's encrypted .keys backup with a different mnemonic
| Severity | medium |
| Confidence | high |
| Category | other |
| CWE | CWE-362, CWE-799 |
| Audited | f50f4c48 (run eceaea44e9f0) |
Affected
lib/views/create_wallet.dartL271-L288lib/views/create_wallet.dartL361-L376
What
Introduced by the diff. The new passphrase sheet's Confirm runs await viewModel.createWallet() with no Navigator.pop on success and no in-flight guard (LongPrimaryButton has no busy/disabled state). Two rapid taps call createWallet() twice concurrently: each _createWallet() generates a fresh Mnemonic.create(WordCount.words12), and both write the SAME *.keys file via File(keys).writeAsBytesSync (last-writer-wins). The two executions then each push NewWalletInfoScreen/WalletHome on the root navigator, so the user is shown the first seed on the info pages while the on-disk wallet holds the second mnemonic — after restart the wallet derives keys the user never backed up. Because the modal is isDismissible: false and never popped before createWallet() pushes the next route (via Navigator.of(c!)), the sheet with the filled, masked passphrase and a live Confirm stays mounted underneath the wallet terminal screens (NewWalletInfoScreen/WalletHome are canPop: false, so the buried sheet is not directly reachable on success but is reachable whenever the create flow errors/retries). While the unguarded double-submit class also existed on the base's Continue button, the new sheet is a new creation entry point with the same flaw and the modal-dismissal regression is new.
Remediation
In the Confirm handler, guard against concurrent execution (e.g. a Future<bool> _creating in-flight flag or disable the button while createWallet() runs) and Navigator.pop() the sheet before/after a successful createWallet(). Prefer pushing the post-creation screens only after the sheet route is removed (pop the modal, then navigate).
Posted from the Cake security-audit bot. Use the ❌ False positive button in Slack if this is not a real issue.
Add an updated passphrase prompt on wallet creation.