CVE-2021-3331: Other (NVD-CWE-Other)
value: WinSCP before 5.17.10 allows remote attackers to execute arbitrary programs when the URL handler encounters a crafted URL that loads session settings. (For example, this is exploitable in a default installation in which WinSCP is the handler for sftp:// URLs.)
CWE description: NVD is only using a subset of CWE for mapping instead of the entire CWE, and the weakness type is not covered by that subset.
CVSS v3 base score: 9.8
Published: 2021-01-27T21:15Z
Repository: https://github.com/winscp/winscp
Language: C++
Files changed: source/Console.cbproj, source/DragExt.cbproj, source/WinSCP.cbproj, source/core/SessionData.cpp, source/core/SessionData.h, source/forms/Custom.cpp, source/windows/ConsoleRunner.cpp, source/windows/WinMain.cpp
Commit date: 2021-01-22 00:43:21 +0100
Commit message: Bug 1943: Prevent loading session settings that can lead to remote code execution from handled URLs

https://winscp.net/tracker/1943
(cherry picked from commit ec584f5189a856cd79509f754722a6898045c5e0)

Source commit: 0f4be408b3f01132b00682da72d925d6c4ee649b

Diff: diff --git a/source/Console.cbproj b/source/Console.cbproj
index 411e390a7..9452df79c 100644
--- a/source/Console.cbproj
+++ b/source/Console.cbproj
@@ -41,11 +41,11 @@
 		<OutputExt>com</OutputExt>
 		<PackageImports>rtl.bpi;$(PackageImports)</PackageImports>
 		<ProjectType>CppConsoleApplication</ProjectType>
 		<SanitizedProjectName>Console</SanitizedProjectName>
 		<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
-		<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Console interface for WinSCP;FileVersion=5.0.1.0;InternalName=console;LegalCopyright=(c) 2000-2020 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.com;ProductName=WinSCP;ProductVersion=5.17.10.0;ReleaseType=stable;WWW=https://winscp.net/</VerInfo_Keys>
+		<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Console interface for WinSCP;FileVersion=5.0.1.0;InternalName=console;LegalCopyright=(c) 2000-2021 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.com;ProductName=WinSCP;ProductVersion=5.17.10.0;ReleaseType=stable;WWW=https://winscp.net/</VerInfo_Keys>
 		<VerInfo_Locale>1033</VerInfo_Locale>
 		<VerInfo_MajorVer>5</VerInfo_MajorVer>
 		<VerInfo_MinorVer>0</VerInfo_MinorVer>
 		<VerInfo_Release>1</VerInfo_Release>
 	</PropertyGroup>
diff --git a/source/DragExt.cbproj b/source/DragExt.cbproj
index bd9e7e369..b349383f1 100644
--- a/source/DragExt.cbproj
+++ b/source/DragExt.cbproj
@@ -47,11 +47,11 @@
 		<PackageImports>rtl.bpi;$(PackageImports)</PackageImports>
 		<ProjectType>CppDynamicLibrary</ProjectType>
 		<SanitizedProjectName>DragExt</SanitizedProjectName>
 		<VerInfo_DLL>true</VerInfo_DLL>
 		<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
-		<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Drag&amp;Drop shell extension for WinSCP ($(Platform));FileVersion=2.0.0.0;InternalName=dragext;LegalCopyright=(c) 2000-2020 Martin Prikryl;LegalTrademarks=;OriginalFilename=dragext.dll;ProductName=WinSCP;ProductVersion=5.17.10.0;ReleaseType=stable;WWW=https://winscp.net/</VerInfo_Keys>
+		<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Drag&amp;Drop shell extension for WinSCP ($(Platform));FileVersion=2.0.0.0;InternalName=dragext;LegalCopyright=(c) 2000-2021 Martin Prikryl;LegalTrademarks=;OriginalFilename=dragext.dll;ProductName=WinSCP;ProductVersion=5.17.10.0;ReleaseType=stable;WWW=https://winscp.net/</VerInfo_Keys>
 		<VerInfo_Locale>1033</VerInfo_Locale>
 		<VerInfo_MajorVer>2</VerInfo_MajorVer>
 	</PropertyGroup>
 	<PropertyGroup Condition="'$(Base_Win64)'!=''">
 		<OutputName>DragExt64</OutputName>
diff --git a/source/WinSCP.cbproj b/source/WinSCP.cbproj
index 5bc53ea4d..107080ba6 100644
--- a/source/WinSCP.cbproj
+++ b/source/WinSCP.cbproj
@@ -74,11 +74,11 @@
 		<OutputExt>exe</OutputExt>
 		<ProjectType>CppVCLApplication</ProjectType>
 		<SanitizedProjectName>WinSCP</SanitizedProjectName>
 		<UsingDelphiRTL>true</UsingDelphiRTL>
 		<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
-		<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=WinSCP: SFTP, FTP, WebDAV, S3 and SCP client;FileVersion=5.17.10.0;InternalName=winscp;LegalCopyright=(c) 2000-2020 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.exe;ProductName=WinSCP;ProductVersion=5.17.10.0;ReleaseType=stable;WWW=https://winscp.net/</VerInfo_Keys>
+		<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=WinSCP: SFTP, FTP, WebDAV, S3 and SCP client;FileVersion=5.17.10.0;InternalName=winscp;LegalCopyright=(c) 2000-2021 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.exe;ProductName=WinSCP;ProductVersion=5.17.10.0;ReleaseType=stable;WWW=https://winscp.net/</VerInfo_Keys>
 		<VerInfo_Locale>1033</VerInfo_Locale>
 		<VerInfo_MajorVer>5</VerInfo_MajorVer>
 		<VerInfo_MinorVer>17</VerInfo_MinorVer>
 		<VerInfo_Release>10</VerInfo_Release>
 	</PropertyGroup>
diff --git a/source/core/SessionData.cpp b/source/core/SessionData.cpp
index 3c16368be..77da3cf0b 100644
--- a/source/core/SessionData.cpp
+++ b/source/core/SessionData.cpp
@@ -594,11 +594,11 @@ bool __fastcall TSessionData::IsSameSite(const TSessionData * Other)
 bool __fastcall TSessionData::IsInFolderOrWorkspace(UnicodeString AFolder)
 {
   return StartsText(UnixIncludeTrailingBackslash(AFolder), Name);
 }
 //---------------------------------------------------------------------
-void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyImport, bool & RewritePassword)
+void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyImport, bool & RewritePassword, bool Unsafe)
 {
   // Make sure we only ever use methods supported by TOptionsStorage
   // (implemented by TOptionsIniFile)
 
   PortNumber = Storage->ReadInteger(L"PortNumber", PortNumber);
@@ -666,11 +666,14 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyI
   Ssh2DES = Storage->ReadBool(L"Ssh2DES", Ssh2DES);
   SshNoUserAuth = Storage->ReadBool(L"SshNoUserAuth", SshNoUserAuth);
   CipherList = Storage->ReadString(L"Cipher", CipherList);
   KexList = Storage->ReadString(L"KEX", KexList);
   HostKeyList = Storage->ReadString(L"HostKey", HostKeyList);
-  GssLibList = Storage->ReadString(L"GSSLibs", GssLibList);
+  if (!Unsafe)
+  {
+    GssLibList = Storage->ReadString(L"GSSLibs", GssLibList);
+  }
   GssLibCustom = Storage->ReadString(L"GSSCustom", GssLibCustom);
   PublicKeyFile = Storage->ReadString(L"PublicKeyFile", PublicKeyFile);
   AddressFamily = static_cast<TAddressFamily>
     (Storage->ReadInteger(L"AddressFamily", AddressFamily));
   RekeyData = Storage->ReadString(L"RekeyBytes", RekeyData);
@@ -688,26 +691,35 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyI
   ResolveSymlinks = Storage->ReadBool(L"ResolveSymlinks", ResolveSymlinks);
   FollowDirectorySymlinks = Storage->ReadBool(L"FollowDirectorySymlinks", FollowDirectorySymlinks);
   DSTMode = (TDSTMode)Storage->ReadInteger(L"ConsiderDST", DSTMode);
   LockInHome = Storage->ReadBool(L"LockInHome", LockInHome);
   Special = Storage->ReadBool(L"Special", Special);
-  Shell = Storage->ReadString(L"Shell", Shell);
+  if (!Unsafe)
+  {
+    Shell = Storage->ReadString(L"Shell", Shell);
+  }
   ClearAliases = Storage->ReadBool(L"ClearAliases", ClearAliases);
   UnsetNationalVars = Storage->ReadBool(L"UnsetNationalVars", UnsetNationalVars);
-  ListingCommand = Storage->ReadString(L"ListingCommand",
-    Storage->ReadBool(L"AliasGroupList", false) ? UnicodeString(L"ls -gla") : ListingCommand);
+  if (!Unsafe)
+  {
+    ListingCommand = Storage->ReadString(L"ListingCommand",
+      Storage->ReadBool(L"AliasGroupList", false) ? UnicodeString(L"ls -gla") : ListingCommand);
+  }
   IgnoreLsWarnings = Storage->ReadBool(L"IgnoreLsWarnings", IgnoreLsWarnings);
   SCPLsFullTime = TAutoSwitch(Storage->ReadInteger(L"SCPLsFullTime", SCPLsFullTime));
   Scp1Compatibility = Storage->ReadBool(L"Scp1Compatibility", Scp1Compatibility);
   TimeDifference = Storage->ReadFloat(L"TimeDifference", TimeDifference);
   TimeDifferenceAuto = Storage->ReadBool(L"TimeDifferenceAuto", (TimeDifference == TDateTime()));
-  DeleteToRecycleBin = Storage->ReadBool(L"DeleteToRecycleBin", DeleteToRecycleBin);
-  OverwrittenToRecycleBin = Storage->ReadBool(L"OverwrittenToRecycleBin", OverwrittenToRecycleBin);
-  RecycleBinPath = Storage->ReadString(L"RecycleBinPath", RecycleBinPath);
-  PostLoginCommands = Storage->ReadString(L"PostLoginCommands", PostLoginCommands);
+  if (!Unsafe)
+  {
+    DeleteToRecycleBin = Storage->ReadBool(L"DeleteToRecycleBin", DeleteToRecycleBin);
+    OverwrittenToRecycleBin = Storage->ReadBool(L"OverwrittenToRecycleBin", OverwrittenToRecycleBin);
+    RecycleBinPath = Storage->ReadString(L"RecycleBinPath", RecycleBinPath);
+    PostLoginCommands = Storage->ReadString(L"PostLoginCommands", PostLoginCommands);
+    ReturnVar = Storage->ReadString(L"ReturnVar", ReturnVar);
+  }
 
-  ReturnVar = Storage->ReadString(L"ReturnVar", ReturnVar);
   ExitCode1IsError = Storage->ReadBool(L"ExitCode1IsError", ExitCode1IsError);
   LookupUserGroups = TAutoSwitch(Storage->ReadInteger(L"LookupUserGroups2", LookupUserGroups));
   EOLType = (TEOLType)Storage->ReadInteger(L"EOLType", EOLType);
   TrimVMSVersions = Storage->ReadBool(L"TrimVMSVersions", TrimVMSVersions);
   NotUtf = TAutoSwitch(Storage->ReadInteger(L"Utf", Storage->ReadInteger(L"SFTPUtfBug", NotUtf)));
@@ -738,17 +750,20 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyI
   {
     // load encrypted password
     RawByteString AProxyPassword = Storage->ReadStringAsBinaryData(L"ProxyPasswordEnc", FProxyPassword);
     SET_SESSION_PROPERTY_FROM(ProxyPassword, AProxyPassword);
   }
-  if (ProxyMethod == pmCmd)
+  if (!Unsafe)
   {
-    ProxyLocalCommand = Storage->ReadStringRaw(L"ProxyTelnetCommand", ProxyLocalCommand);
-  }
-  else
-  {
-    ProxyTelnetCommand = Storage->ReadStringRaw(L"ProxyTelnetCommand", ProxyTelnetCommand);
+    if (ProxyMethod == pmCmd)
+    {
+      ProxyLocalCommand = Storage->ReadStringRaw(L"ProxyTelnetCommand", ProxyLocalCommand);
+    }
+    else
+    {
+      ProxyTelnetCommand = Storage->ReadStringRaw(L"ProxyTelnetCommand", ProxyTelnetCommand);
+    }
   }
   ProxyDNS = TAutoSwitch((Storage->ReadInteger(L"ProxyDNS", (ProxyDNS + 2) % 3) + 1) % 3);
   ProxyLocalhost = Storage->ReadBool(L"ProxyLocalhost", ProxyLocalhost);
 
   #define READ_BUG(BUG) \
@@ -773,11 +788,14 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyI
       Storage->ReadBool(L"BuggyMAC", false))
   {
       Bug[sbHMAC2] = asOn;
   }
 
-  SftpServer = Storage->ReadString(L"SftpServer", SftpServer);
+  if (!Unsafe)
+  {
+    SftpServer = Storage->ReadString(L"SftpServer", SftpServer);
+  }
   #define READ_SFTP_BUG(BUG) \
     SFTPBug[sb##BUG] = TAutoSwitch(Storage->ReadInteger(L"SFTP" #BUG "Bug", SFTPBug[sb##BUG]));
   READ_SFTP_BUG(Symlink);
   READ_SFTP_BUG(SignedTS);
   #undef READ_SFTP_BUG
@@ -918,11 +936,11 @@ void __fastcall TSessionData::Load(THierarchicalStorage * Storage, bool PuttyImp
     // this breaks sites reload and consequently an overal operation,
     // such as opening Sites menu
     ClearSessionPasswords();
     FProxyPassword = L"";
 
-    DoLoad(Storage, PuttyImport, RewritePassword);
+    DoLoad(Storage, PuttyImport, RewritePassword, false);
 
     Storage->CloseSubKey();
   }
 
   if (RewritePassword)
@@ -1939,10 +1957,11 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
   if (AProtocolDefined != NULL)
   {
     *AProtocolDefined = ProtocolDefined;
   }
 
+  bool Unsafe = FLAGSET(Flags, pufUnsafe);
   if (!Url.IsEmpty())
   {
     UnicodeString DecodedUrl = DecodeUrlChars(Url);
     // lookup stored session even if protocol was defined
     // (this allows setting for example default username for host
@@ -2103,11 +2122,11 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
         }
       }
 
       if (RawSettings->Count > 0) // optimization
       {
-        ApplyRawSettings(RawSettings.get());
+        ApplyRawSettings(RawSettings.get(), FLAGSET(Flags, pufUnsafe));
       }
 
       bool HasPassword = (UserInfo.Pos(L':') > 0);
       UnicodeString RawUserName = CutToChar(UserInfo, L':', false);
       UserName = DecodeUrlChars(RawUserName);
@@ -2252,28 +2271,28 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
     if (Options->FindSwitch(RawSettingsOption))
     {
       std::unique_ptr<TStrings> RawSettings(new TStringList());
       if (Options->FindSwitch(RawSettingsOption, RawSettings.get()))
       {
-        ApplyRawSettings(RawSettings.get());
+        ApplyRawSettings(RawSettings.get(), Unsafe);
       }
     }
   }
 
   return true;
 }
 //---------------------------------------------------------------------
-void __fastcall TSessionData::ApplyRawSettings(TStrings * RawSettings)
+void __fastcall TSessionData::ApplyRawSettings(TStrings * RawSettings, bool Unsafe)
 {
   std::unique_ptr<TOptionsStorage> OptionsStorage(new TOptionsStorage(RawSettings, false));
-  ApplyRawSettings(OptionsStorage.get());
+  ApplyRawSettings(OptionsStorage.get(), Unsafe);
 }
 //---------------------------------------------------------------------
-void __fastcall TSessionData::ApplyRawSettings(THierarchicalStorage * Storage)
+void __fastcall TSessionData::ApplyRawSettings(THierarchicalStorage * Storage, bool Unsafe)
 {
   bool Dummy;
-  DoLoad(Storage, false, Dummy);
+  DoLoad(Storage, false, Dummy, Unsafe);
 }
 //---------------------------------------------------------------------
 void __fastcall TSessionData::ConfigureTunnel(int APortNumber)
 {
   FOrigHostName = HostName;
diff --git a/source/core/SessionData.h b/source/core/SessionData.h
index 82a17b4b2..f46cbeb4e 100644
--- a/source/core/SessionData.h
+++ b/source/core/SessionData.h
@@ -53,10 +53,11 @@ enum TSessionUrlFlags
   sufOpen = sufUserName | sufPassword
 };
 enum TParseUrlFlags
 {
   pufAllowStoredSiteWithProtocol = 0x01,
+  pufUnsafe = 0x02,
 };
 //---------------------------------------------------------------------------
 extern const UnicodeString CipherNames[CIPHER_COUNT];
 extern const UnicodeString KexNames[KEX_COUNT];
 extern const UnicodeString HostKeyNames[HOSTKEY_COUNT];
@@ -413,11 +414,11 @@ private:
   void __fastcall SavePasswords(THierarchicalStorage * Storage, bool PuttyExport, bool DoNotEncryptPasswords, bool SaveAll);
   UnicodeString __fastcall GetLocalName();
   UnicodeString __fastcall GetFolderName();
   void __fastcall Modify();
   UnicodeString __fastcall GetSource();
-  void __fastcall DoLoad(THierarchicalStorage * Storage, bool PuttyImport, bool & RewritePassword);
+  void __fastcall DoLoad(THierarchicalStorage * Storage, bool PuttyImport, bool & RewritePassword, bool Unsafe);
   void __fastcall DoSave(THierarchicalStorage * Storage,
     bool PuttyExport, const TSessionData * Default, bool DoNotEncryptPasswords);
   UnicodeString __fastcall ReadXmlNode(_di_IXMLNode Node, const UnicodeString & Name, const UnicodeString & Default);
   int __fastcall ReadXmlNode(_di_IXMLNode Node, const UnicodeString & Name, int Default);
   _di_IXMLNode __fastcall FindSettingsNode(_di_IXMLNode Node, const UnicodeString & Name);
@@ -466,12 +467,12 @@ public:
   TSessionData * __fastcall Clone();
   void __fastcall Default();
   void __fastcall DefaultSettings();
   void __fastcall NonPersistant();
   void __fastcall Load(THierarchicalStorage * Storage, bool PuttyImport);
-  void __fastcall ApplyRawSettings(TStrings * RawSettings);
-  void __fastcall ApplyRawSettings(THierarchicalStorage * Storage);
+  void __fastcall ApplyRawSettings(TStrings * RawSettings, bool Unsafe);
+  void __fastcall ApplyRawSettings(THierarchicalStorage * Storage, bool Unsafe);
   void __fastcall ImportFromFilezilla(_di_IXMLNode Node, const UnicodeString & Path, _di_IXMLNode SettingsNode);
   void __fastcall Save(THierarchicalStorage * Storage, bool PuttyExport,
     const TSessionData * Default = NULL);
   void __fastcall SaveRecryptedPasswords(THierarchicalStorage * Storage);
   void __fastcall RecryptPasswords();
diff --git a/source/forms/Custom.cpp b/source/forms/Custom.cpp
index 318c484cd..328257657 100644
--- a/source/forms/Custom.cpp
+++ b/source/forms/Custom.cpp
@@ -1505,11 +1505,11 @@ bool __fastcall TSiteRawDialog::Execute(TSessionData * Data)
     Data->PortNumber = BackupData->PortNumber;
     Data->UserName = BackupData->UserName;
     Data->Password = BackupData->Password;
     Data->Ftps = BackupData->Ftps;
 
-    Data->ApplyRawSettings(SettingsMemo->Lines);
+    Data->ApplyRawSettings(SettingsMemo->Lines, false);
   }
   return Result;
 }
 //---------------------------------------------------------------------------
 void __fastcall TSiteRawDialog::SettingsMemoKeyDown(TObject * Sender, WORD & Key, TShiftState Shift)
diff --git a/source/windows/ConsoleRunner.cpp b/source/windows/ConsoleRunner.cpp
index 1c937e364..34781e6c9 100644
--- a/source/windows/ConsoleRunner.cpp
+++ b/source/windows/ConsoleRunner.cpp
@@ -2366,11 +2366,11 @@ int __fastcall BatchSettings(TConsole * Console, TProgramParams * Params)
               Mask.Matches(Data->Name, false, false))
           {
             Matches++;
             std::unique_ptr<TSessionData> OriginalData(new TSessionData(L""));
             OriginalData->CopyDataNoRecrypt(Data);
-            Data->ApplyRawSettings(OptionsStorage.get());
+            Data->ApplyRawSettings(OptionsStorage.get(), false);
             bool Changed = !OriginalData->IsSame(Data, false);
             if (Changed)
             {
               Changes++;
             }
diff --git a/source/windows/WinMain.cpp b/source/windows/WinMain.cpp
index b44e2166e..2ded435e4 100644
--- a/source/windows/WinMain.cpp
+++ b/source/windows/WinMain.cpp
@@ -1094,11 +1094,14 @@ int __fastcall Execute()
       {
         Retry = false;
         std::unique_ptr<TObjectList> DataList(new TObjectList());
         try
         {
-          GetLoginData(AutoStartSession, Params, DataList.get(), DownloadFile, NeedSession, NULL, pufAllowStoredSiteWithProtocol);
+          int Flags =
+            pufAllowStoredSiteWithProtocol |
+            FLAGMASK(!CheckSafe(Params), pufUnsafe);
+          GetLoginData(AutoStartSession, Params, DataList.get(), DownloadFile, NeedSession, NULL, Flags);
           // GetLoginData now Aborts when session is needed and none is selected
           if (DebugAlwaysTrue(!NeedSession || (DataList->Count > 0)))
           {
             if (CheckSafe(Params))
             {

Vulnerable code: 		<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Console interface for WinSCP;FileVersion=5.0.1.0;InternalName=console;LegalCopyright=(c) 2000-2020 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.com;ProductName=WinSCP;ProductVersion=5.17.10.0;ReleaseType=stable;WWW=https://winscp.net/</VerInfo_Keys>
		<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Drag&amp;Drop shell extension for WinSCP ($(Platform));FileVersion=2.0.0.0;InternalName=dragext;LegalCopyright=(c) 2000-2020 Martin Prikryl;LegalTrademarks=;OriginalFilename=dragext.dll;ProductName=WinSCP;ProductVersion=5.17.10.0;ReleaseType=stable;WWW=https://winscp.net/</VerInfo_Keys>
		<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=WinSCP: SFTP, FTP, WebDAV, S3 and SCP client;FileVersion=5.17.10.0;InternalName=winscp;LegalCopyright=(c) 2000-2020 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.exe;ProductName=WinSCP;ProductVersion=5.17.10.0;ReleaseType=stable;WWW=https://winscp.net/</VerInfo_Keys>
void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyImport, bool & RewritePassword)
  GssLibList = Storage->ReadString(L"GSSLibs", GssLibList);
  Shell = Storage->ReadString(L"Shell", Shell);
  ListingCommand = Storage->ReadString(L"ListingCommand",
    Storage->ReadBool(L"AliasGroupList", false) ? UnicodeString(L"ls -gla") : ListingCommand);
  DeleteToRecycleBin = Storage->ReadBool(L"DeleteToRecycleBin", DeleteToRecycleBin);
  OverwrittenToRecycleBin = Storage->ReadBool(L"OverwrittenToRecycleBin", OverwrittenToRecycleBin);
  RecycleBinPath = Storage->ReadString(L"RecycleBinPath", RecycleBinPath);
  PostLoginCommands = Storage->ReadString(L"PostLoginCommands", PostLoginCommands);
  ReturnVar = Storage->ReadString(L"ReturnVar", ReturnVar);
  if (ProxyMethod == pmCmd)
    ProxyLocalCommand = Storage->ReadStringRaw(L"ProxyTelnetCommand", ProxyLocalCommand);
  }
  else
  {
    ProxyTelnetCommand = Storage->ReadStringRaw(L"ProxyTelnetCommand", ProxyTelnetCommand);
  SftpServer = Storage->ReadString(L"SftpServer", SftpServer);
    DoLoad(Storage, PuttyImport, RewritePassword);
        ApplyRawSettings(RawSettings.get());
        ApplyRawSettings(RawSettings.get());
void __fastcall TSessionData::ApplyRawSettings(TStrings * RawSettings)
  ApplyRawSettings(OptionsStorage.get());
void __fastcall TSessionData::ApplyRawSettings(THierarchicalStorage * Storage)
  DoLoad(Storage, false, Dummy);
  void __fastcall DoLoad(THierarchicalStorage * Storage, bool PuttyImport, bool & RewritePassword);
  void __fastcall ApplyRawSettings(TStrings * RawSettings);
  void __fastcall ApplyRawSettings(THierarchicalStorage * Storage);
    Data->ApplyRawSettings(SettingsMemo->Lines);
            Data->ApplyRawSettings(OptionsStorage.get());
          GetLoginData(AutoStartSession, Params, DataList.get(), DownloadFile, NeedSession, NULL, pufAllowStoredSiteWithProtocol);
Fixed code: 		<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Console interface for WinSCP;FileVersion=5.0.1.0;InternalName=console;LegalCopyright=(c) 2000-2021 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.com;ProductName=WinSCP;ProductVersion=5.17.10.0;ReleaseType=stable;WWW=https://winscp.net/</VerInfo_Keys>
		<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Drag&amp;Drop shell extension for WinSCP ($(Platform));FileVersion=2.0.0.0;InternalName=dragext;LegalCopyright=(c) 2000-2021 Martin Prikryl;LegalTrademarks=;OriginalFilename=dragext.dll;ProductName=WinSCP;ProductVersion=5.17.10.0;ReleaseType=stable;WWW=https://winscp.net/</VerInfo_Keys>
		<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=WinSCP: SFTP, FTP, WebDAV, S3 and SCP client;FileVersion=5.17.10.0;InternalName=winscp;LegalCopyright=(c) 2000-2021 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.exe;ProductName=WinSCP;ProductVersion=5.17.10.0;ReleaseType=stable;WWW=https://winscp.net/</VerInfo_Keys>
void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyImport, bool & RewritePassword, bool Unsafe)
  if (!Unsafe)
  {
    GssLibList = Storage->ReadString(L"GSSLibs", GssLibList);
  }
  if (!Unsafe)
  {
    Shell = Storage->ReadString(L"Shell", Shell);
  }
  if (!Unsafe)
  {
    ListingCommand = Storage->ReadString(L"ListingCommand",
      Storage->ReadBool(L"AliasGroupList", false) ? UnicodeString(L"ls -gla") : ListingCommand);
  }
  if (!Unsafe)
  {
    DeleteToRecycleBin = Storage->ReadBool(L"DeleteToRecycleBin", DeleteToRecycleBin);
    OverwrittenToRecycleBin = Storage->ReadBool(L"OverwrittenToRecycleBin", OverwrittenToRecycleBin);
    RecycleBinPath = Storage->ReadString(L"RecycleBinPath", RecycleBinPath);
    PostLoginCommands = Storage->ReadString(L"PostLoginCommands", PostLoginCommands);
    ReturnVar = Storage->ReadString(L"ReturnVar", ReturnVar);
  }
  if (!Unsafe)
    if (ProxyMethod == pmCmd)
    {
      ProxyLocalCommand = Storage->ReadStringRaw(L"ProxyTelnetCommand", ProxyLocalCommand);
    }
    else
    {
      ProxyTelnetCommand = Storage->ReadStringRaw(L"ProxyTelnetCommand", ProxyTelnetCommand);
    }
  if (!Unsafe)
  {
    SftpServer = Storage->ReadString(L"SftpServer", SftpServer);
  }
    DoLoad(Storage, PuttyImport, RewritePassword, false);
  bool Unsafe = FLAGSET(Flags, pufUnsafe);
        ApplyRawSettings(RawSettings.get(), FLAGSET(Flags, pufUnsafe));
        ApplyRawSettings(RawSettings.get(), Unsafe);
void __fastcall TSessionData::ApplyRawSettings(TStrings * RawSettings, bool Unsafe)
  ApplyRawSettings(OptionsStorage.get(), Unsafe);
void __fastcall TSessionData::ApplyRawSettings(THierarchicalStorage * Storage, bool Unsafe)
  DoLoad(Storage, false, Dummy, Unsafe);
  pufUnsafe = 0x02,
  void __fastcall DoLoad(THierarchicalStorage * Storage, bool PuttyImport, bool & RewritePassword, bool Unsafe);
  void __fastcall ApplyRawSettings(TStrings * RawSettings, bool Unsafe);
  void __fastcall ApplyRawSettings(THierarchicalStorage * Storage, bool Unsafe);
    Data->ApplyRawSettings(SettingsMemo->Lines, false);
            Data->ApplyRawSettings(OptionsStorage.get(), false);
          int Flags =
            pufAllowStoredSiteWithProtocol |
            FLAGMASK(!CheckSafe(Params), pufUnsafe);
          GetLoginData(AutoStartSession, Params, DataList.get(), DownloadFile, NeedSession, NULL, Flags);