Store the passphrase in a zeroizing buffer instead of a TextEdit#2
Open
domenkozar wants to merge 1 commit into
Open
Store the passphrase in a zeroizing buffer instead of a TextEdit#2domenkozar wants to merge 1 commit into
domenkozar wants to merge 1 commit into
Conversation
Feed keystrokes directly into a zeroize::Zeroizing<String> and draw a masked view, rather than an egui TextEdit whose retained widget state and undo history keep the plaintext around after the dialog closes. Move the value into the SecretString on submit (no clone; the buffer is zeroized on drop). Tests drive the field with synthetic input events since the masked view is no longer an accessible widget.
dsociative
requested changes
Jul 10, 2026
dsociative
left a comment
Owner
There was a problem hiding this comment.
Verified end to end on Wayland/niri (sandboxed offline build, 7/7 tests, clean strace). The zeroizing approach is exactly right and I want to land this first — two items:
- (blocking) The masked field lost its caret and focus indication. The bullet view is a non-focusable
Label, so egui draws neither a caret nor a focus outline — side by side with main the field looks dead even though keystrokes register. Could you add manual focus/caret visuals (e.g. a focus-styledFramestroke plus a caret painted after the last bullet), or otherwise restore the affordance? You know egui internals better than I do — pick whatever shape you prefer. - (nit) #3 pre-reserves the buffer (
String::with_capacity(256)) so ordinary typing never reallocates mid-entry and leaves unzeroized copies behind; since this PR can land standalone, it would be nice to have that here too.
Note: Event::Paste works fine here on top of eframe, but stops firing in the #3 stack — tracked in the #3 review, nothing to do in this PR.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is the first change proposed in #1 (zeroizing input), as a standalone, minimal PR that doesn't touch the design discussions (no grab, no rendering change).
Problem
The passphrase field uses
TextEdit::singleline(&mut password).password(true)on aString, thenSecretString::from(password.clone())+password.clear(). So the plaintext:clone(), andclear()doesn't zeroize the buffer.Change
PinDialogState.passwordis now azeroize::Zeroizing<String>.Event::Text/Event::Paste/Backspace) are fed straight into it and a masked bullet view is drawn, instead of aTextEdit, so the plaintext never enters egui's retained state or undo history.SecretStringwithmem::take(noclone; the buffer is zeroized on drop).accesskitdev-dependency is dropped (no longer used).No change to the Assuan protocol or the dialog UX.
zeroizeis added as a direct dependency; it is already in the tree transitively viasecrecy.Refs #1.