You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Eliminate the security risk of storing the naked, raw Master Key inside a standard Go struct on the managed heap long-term (Session.masterKey, internal/features/auth/service.go:36). Prevent memory dump exploits and operating system swap space leaks while maintaining a seamless user session.
Why now
Today the master key is held as a plain []byte in the in-memory Session for the whole signed-in lifetime, and Logout() merely drops the reference — the bytes stay on the heap until GC reuses them. This issue is the concrete hardening for the "no idle timeout / master key handling" gap in #63.
Technical Requirements
Integrate the memguard library into the application.
Immediately after deriving the Master Key at login/registration, split it into two components via an XOR loop (A ⊕ B = C).
Store Piece A in memory inside an unswappable, encrypted memguard.Enclave.
Store Piece B securely outside the app heap inside the macOS Keychain (or the equivalent OS secret store on other platforms, e.g. via the existing internal/platform/keyring wrapper).
Immediately overwrite the temporary, raw Master Key bytes with zeros (0x00) to scrub them from the Go garbage collector's scope.
Implement a dynamic reconstruction function: whenever a file operation occurs,
read Piece B from Keychain,
pull Piece A from the enclave,
XOR them back together inside a temporary memguard.LockedBuffer,
execute the AES operation,
immediately invoke .Destroy().
Acceptance Criteria
The raw plaintext Master Key never stays resident in a standard Go struct or global variable.
Memory profiling shows no persistent plaintext keys sitting on the Go heap.
File decryption successfully reconstructs the key on-demand via XOR without asking the user to re-enter their password.
Temporary buffers holding reconstructed keys are explicitly zeroed/destroyed immediately after execution.
Logout / session expiry handling
On Logout (Service.Logout, service.go:492): destroy Piece A in the enclave, wipe the locked buffer, and zero any transient reconstruction buffers. Decide whether Piece B is also deleted from the Keychain at logout or kept for the next login — it should be kept (it is useless without Piece A and is derived from the session), so the app must also handle the case where a Keychain Piece B exists but no enclave Piece A does (e.g. after a crash/restart) and clean it up.
On session expiry / app restart: the session is in-memory only, so both pieces are already gone; ensure no orphaned Keychain entries accumulate (see the crash case above).
Objective
Eliminate the security risk of storing the naked, raw Master Key inside a standard Go struct on the managed heap long-term (
Session.masterKey,internal/features/auth/service.go:36). Prevent memory dump exploits and operating system swap space leaks while maintaining a seamless user session.Why now
Today the master key is held as a plain
[]bytein the in-memorySessionfor the whole signed-in lifetime, andLogout()merely drops the reference — the bytes stay on the heap until GC reuses them. This issue is the concrete hardening for the "no idle timeout / master key handling" gap in #63.Technical Requirements
Integrate the memguard library into the application.
Immediately after deriving the Master Key at login/registration, split it into two components via an XOR loop (
A ⊕ B = C).Store Piece A in memory inside an unswappable, encrypted
memguard.Enclave.Store Piece B securely outside the app heap inside the macOS Keychain (or the equivalent OS secret store on other platforms, e.g. via the existing
internal/platform/keyringwrapper).Immediately overwrite the temporary, raw Master Key bytes with zeros (
0x00) to scrub them from the Go garbage collector's scope.Implement a dynamic reconstruction function: whenever a file operation occurs,
memguard.LockedBuffer,.Destroy().Acceptance Criteria
Logout / session expiry handling
Service.Logout, service.go:492): destroy Piece A in the enclave, wipe the locked buffer, and zero any transient reconstruction buffers. Decide whether Piece B is also deleted from the Keychain at logout or kept for the next login — it should be kept (it is useless without Piece A and is derived from the session), so the app must also handle the case where a Keychain Piece B exists but no enclave Piece A does (e.g. after a crash/restart) and clean it up.Scope
internal/shared/crypto— XOR split/combine helpers (tested).internal/features/auth/service.go— store/derive/teardown integration.internal/features/settings+upload/download— swapMasterKey()consumers to the on-demand reconstruction API.github.com/awnumar/memguard.