#3418·mRemoteNG

Master password change can silently fail to save: root node raises no PropertyChanged, and default SaveConnectionsFrequency skips the exit save

Author: jafinCreated Aug 10, 2026Updated Aug 10, 2026

Summary

Setting or clearing the connection file's master password ("Password Protect" on the root node) can fail to reach disk with no indication to the user. Two independent gaps combine: the root node's password properties raise no PropertyChanged, so the save-on-edit path never fires; and on a default profile SaveConnectionsFrequency is Unassigned, so the shutdown path returns without saving either.

The consequence is security-relevant rather than merely inconvenient. A user who sets a master password and closes mRemoteNG can be left with a connection file still encrypted under the built-in mR3m constant, while the UI gave every indication the change was applied.

This is from reading the code on v1.78.2-dev, not from a runtime repro — flagging that up front so it can be confirmed before anyone acts on it.

Cause 1 — root node password properties raise no change notification

RootNodeInfo declares Password as a plain auto-property that hides the base implementation:

https://github.com/mRemoteNG/mRemoteNG/blob/v1.78.2-dev/mRemoteNG/Tree/Root/RootNodeInfo.cs#L41

csharp
public new bool Password { get; set; }

The hidden base property does notify (mRemoteNG/Connection/AbstractConnectionRecord.cs:260-263):

csharp
public virtual string Password
{
    get => GetPropertyValue("Password", _password);
    set => SetField(ref _password, value, "Password");
}

PasswordString / _customPassword (RootNodeInfo.cs:44-52) likewise assign fields directly and raise nothing.

So editing the master password raises no PropertyChanged on the tree model, and SaveConnectionsOnEdit never runs:

https://github.com/mRemoteNG/mRemoteNG/blob/v1.78.2-dev/mRemoteNG/Config/Connections/SaveConnectionsOnEdit.cs#L37-L57

Ordinary edits are unaffected — SaveConnectionsAfterEveryEdit defaults to True and drives that path normally. The master password change simply never reaches it.

Cause 2 — default settings produce no save on exit

SaveConnectionsFrequency defaults to 0, which is ConnectionsBackupFrequencyEnum.Unassigned (mRemoteNG/Properties/OptionsBackupPage.settings:17-19). Shutdown.SaveConnections has no case for it:

https://github.com/mRemoteNG/mRemoteNG/blob/v1.78.2-dev/mRemoteNG/App/Shutdown.cs#L64-L93

csharp
switch (Properties.OptionsBackupPage.Default.SaveConnectionsFrequency)
{
    case (int)ConnectionsBackupFrequencyEnum.Daily:  ...
    case (int)ConnectionsBackupFrequencyEnum.Weekly: ...
    default:
        return;      // Unassigned lands here — no save
}

The migration off Unassigned runs only when the options page is loaded:

https://github.com/mRemoteNG/mRemoteNG/blob/v1.78.2-dev/mRemoteNG/UI/Forms/OptionsPages/ConnectionsPage.cs#L115-L129

so a profile where the user has never opened Tools → Options → Connections stays at Unassigned indefinitely. Note also that the legacy SaveConsOnExit setting still defaults to True but is no longer consulted at shutdown — only that migration reads it. A user who has that box ticked reasonably expects an exit save and does not get one.

Steps to reproduce (expected, unverified)

On a profile that has never opened Tools → Options → Connections:

  1. Set a master password on the connection file via the root node's "Password Protect" property.
  2. File → Save Connections.
  3. Close mRemoteNG.
  4. Reopen — the password is not in effect, and confCons.xml is still readable under the default key.

Suggested fix

  1. Make RootNodeInfo.Password and PasswordString raise PropertyChanged like every other connection property, rather than hiding the notifying base member with silent auto-properties.
  2. Give Shutdown.SaveConnections a defined behaviour for Unassigned — treating it as OnExit matches the legacy SaveConsOnExit default and preserves the user's existing expectation.

More broadly, SaveConnectionsFrequency governs how often to save periodically; it should not be able to decide whether an edit the user has already made is written at all.

Related, lower severity

SaveConnectionsOnEdit.cs:52 drops any edit made while the main form is closing:

csharp
if (FrmMain.Default.IsClosing)
    return;

With cause 2 in play there is then no exit save to catch it. Separate from the above, but the same class of silent loss.

Environment

  • Branch: v1.78.2-dev (at c6018d9d)
  • Windows 11 Pro 23H2