Skip to content

Passwords stay encrypted in memory; editors no longer show stored ones - #70

Merged
GrischaE1 merged 2 commits into
mainfrom
secrets-in-memory
Oct 23, 2026
Merged

GrischaE1 merged 2 commits into
mainfrom
secrets-in-memory

Conversation

@GrischaE1

Copy link
Copy Markdown
Owner

Stored passwords no longer sit in memory as plain strings. They stay encrypted and are decrypted only for the call that uses them. Until now, every stored password was decrypted when the data loaded (local-db-design.md §15 listed this as open). Device sync is marked not planned.

Passwords in memory

  • Secret (Services/Secret.cs) replaces string? Password in CredentialSet and SavedCredential.
    • It is AES-256-GCM with a key made at random for each run, held in pinned memory.
    • Use decrypts into a pinned buffer, hands it over as a span and wipes it afterwards. ToSecureString builds PowerShell's credential straight from that buffer.
    • Equality uses an HMAC fingerprint, compared in constant time without decrypting.
    • ToString() is never the value.
  • Database:
    • SecretBox.OpenSecret opens each secrets row straight into a Secret.
    • A record's JSON carries only a placeholder (SecretJsonConverter.Capture / Supply), so the value never enters the JSON text in either direction.
    • The change tracker hashes fingerprints instead of values.
    • The stored format is unchanged.
  • Files: settings, shared and backup files still write the password as a JSON string, as before. The converter writes and reads it from spans, and the plaintext buffer is wiped once the file is encrypted.
  • Consumers:
    • WNet gets a wiped, null-terminated copy.
    • The agent's Basic header is built from the SecureString in a wiped buffer.
    • The clipboard copy for the Windows Security prompt is written straight from the decrypted buffer.
    • The auto sign-in frame comes from the span.
    • WebDAV gets a SecureString.
    • The RDP control, SMBLibrary, SSH.NET and FluentFTP take only strings. They get one right before the call; §17 lists them.
  • Editors: the connection editor, Saved credentials and the share editor start with an empty password box. It says "A password is stored – type a new one to replace it". An empty box keeps the stored password, and Remove stored password clears it.
  • The agent enrollment keys are keys, not passwords, so they stay strings in the model.

Sync

Device sync (phase 4) is marked not planned in local-db-design.md §8, §12, §13 and §16, and in the notes and scripts designs. The shared settings folder already covers using the same connections on several PCs.

Tests

  • SecretTests:
    • round trip, empty is null, equality
    • JSON stays a plain string, so older versions still read the files
    • a record has no value or placeholder in its JSON
    • the hash is unchanged for the same password; the audit names Credentials.Password
    • SecretBox opens a password only in its own place
    • the editor VM keeps, replaces or removes the password
    • view tests (STA) for Saved credentials and the share editor
  • SecretMemoryTests:
    • Writes a full memory dump of the test process after a random password has gone through Use, SecureString, sealing and opening, a record, and a JSON read.
    • The dump is searched for that password as UTF-8 and UTF-16. A second password turned into a string is the control: it must be found, and the stored one must not.
    • The test never holds either password in one piece (two XOR halves).
  • Lab C-DB-14 (C-DATA.Tests.ps1, client VM):
    • RemoteHub is started again after C-DB-01 stored the lab password, and RemoteHub.exe is dumped in full.
    • Pass: the lab password isn't in the dump as UTF-8 or UTF-16, and the host name (the control) is.
    • Not run in the lab yet (marked ◐). The dump and search helper was checked on Windows PowerShell 5.1 here.
  • Existing tests and the lab harness are updated to the new type.
  • Results:
    • Full unit suite: 1,102 passed, 1 failed, 6 skipped. The failure, HelperClipboardFilesTests.Files_copied_by_another_program_reach_the_helper_as_files, is a clipboard test this PR doesn't touch, and it passed when rerun.
    • The build has no warnings.

Docs

  • local-db-design.md: §5, a new §17 "Passwords in memory" (including where a plain copy still exists), §15 and §16.
  • The README's storage section, the lab case sheet and the test document.

Stored passwords (connections, folders, shares, defaults, saved credentials)
are now a Secret: AES-256-GCM with a per-process key, decrypted only for the
call that uses them into a pinned buffer that is wiped afterwards. Loading
opens each sealed row straight into a Secret; database records carry a
placeholder instead of the value. The editors start with an empty password
box: typing replaces the stored password, Remove stored password clears it.

Tests: Secret unit and view tests, a memory-dump test of the test process,
and lab case C-DB-14 (dump of RemoteHub.exe on the client VM). Device sync is
marked not planned in local-db-design.md.
@gitguardian

gitguardian Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

️✅ There are no secrets present in this pull request anymore.

If these secrets were true positive and are still valid, we highly recommend you to revoke them.
While these secrets were previously flagged, we no longer have a reference to the
specific commits where they were detected. Once a secret has been leaked into a git
repository, you should consider it compromised, even if it was deleted immediately.
Find here more information about risks.


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@github-actions
github-actions Bot marked this pull request as draft October 23, 2026 15:09
@github-actions

Copy link
Copy Markdown

Pull requests start as drafts here. Mark this one Ready for review when it's done and all checks have passed.

@GrischaE1
GrischaE1 marked this pull request as ready for review October 23, 2026 15:42
@GrischaE1
GrischaE1 merged commit 89eebf1 into main Oct 23, 2026
13 checks passed
@GrischaE1
GrischaE1 deleted the secrets-in-memory branch October 23, 2026 15:42
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 23, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant