One of the changes in .NET Framework 4 was the retirement of Code Access Security (CAS). Until recently this was something, I have only read about at the time of release, but it didn’t have any effect on my day to day work. Therefore I was even more surprised that an application which has recently been migrated from .NET 2.0 to .NET 4 suddenly failed to start from the network drive while working flawlessly from the local machine. Wasn’t this problem already resolved with the release of .NET Framework 3.5 SP1 when the FullTrust set of permissions was granted to LocalIntranet zone by default? Obviously not. The issue certainly demanded further investigation.
While the exception thrown by the runtime only hinted at some assembly loading related issue (System.IO.FileLoadException: Could not load file or assembly '<assembly>' or one of its dependencies. Operation is not supported.), its inner exception was much more informative and already pointed at the solution (System.NotSupportedException: An attempt was made to load an assembly from a network location which would have caused the assembly to be sandboxed in previous versions of the .NET Framework. This release of the .NET Framework does not enable CAS policy by default, so this load may be dangerous. If this load is not intended to sandbox the assembly, please enable the loadFromRemoteSources switch. See http://go.microsoft.com/fwlink/?LinkId=155569 for more information.).
The link included in the exception message points to the documentation for the <loadFromRemoteSources> configuration element which provides the solution for the problem – just add this element to the configuration file of your executable and you’re done:
<loadFromRemoteSources enabled="true" />
Though, the page does a really bad job at explaining why this is necessary at all. Sure, it’s something related to loading assemblies from zones which aren’t fully trusted, but it doesn’t happen always. If you deploy an application which references a library in the same folder to a network drive, it will work flawlessly. But if you try to load that same library using Assembly.LoadFrom() instead of referencing it, the problem will manifest itself. The reason being that this method implicitly uses CAS policy. The details are thoroughly discussed in the linked article but essentially the exception is thrown because otherwise the assembly might be loaded with full trust in .NET 4 which would be granted a more restricted permission set in .NET 2.0 because the CAS policy is now disabled. This could be a potential security vulnerability for applications developed for the old framework.
This also means that there is another way to fix the issue in .NET 4 – by enabling the CAS policy with the <NetFx40_LegacySecurityPolicy> configuration element (strangely the <legacyCasPolicy> configuration element has the same effect although it’s not documented anywhere – remains from the beta period, perhaps?):
<NetFx40_LegacySecurityPolicy enabled="true" />
Though, there is a difference between both solutions:
- The first one enables loading of all assemblies from remote locations (other than MyComputer zone) with full trust permission set. Use this only if you know exactly which assemblies your application will be loading, i.e. you have full control over their location and also over the assembly names being passed to the Assembly.LoadFrom() method.
- The second one reverts the security model back to the .NET 2.0 mode, i.e. you have the same control over the granted permission sets as in .NET 2.0 by using the Code Access Security policies.
Keep in mind that both of these solutions should only be used temporarily and in the long run the code should be migrated to the simple sandboxing model, available since .NET 2.0 and the only remaining one in .NET 4.