An interesting question came up in the newsgroups today. If you serialize a permissions set (either by calling ToXml().ToString() directly on the permission, or by converting to an XML Element), you'll get permissions that look like this:
The first attribute of the permission contains the assembly qualified name of the permission, including the version number of mscorlib that the permission is located in. Why doesn't this cause problems when a permission is serialized in one version of the CLR, and restored in another?
The reason is called unification. The CLR itself is tightly bound to the version of mscorlib that it was built with. This is understandable since mscorlib contains many special types, including System.Object, System.String, etc. In fact, the entire framework stack is pretty tightly bound together. For instance, we don't test the v1.0 System.Security.dll against the v1.1 runtime.
In order to allow this to work, starting with v1.1 of the CLR, even if an assembly is built against a different version of the framework, the CLR will load the version of the framework stack that it was built with. So, if you have a v1.0 WinForms app running on the v1.1 runtime, you'll actually get the v1.1 WinForms. Alan Shi gives a good explanation of this in his Unification Policy blog entry.
Given the unification policy, you can easily see what happens here. If I try to deserialize the above v1.0 SecurityPermission on v1.1 or v2.0 of the CLR, when the security system tells the loader to go load mscorlib, it will be unified to the current mscorlib, and the current version of the permission will be loaded.
If you want to prove to yourself that unification is the reason that this works, and there's not some kind of special security system voodoo going on, try it with a custom permission you write. Create a permission, serialize it, and then change the version number. When you try to deserialize that, you'll get an exception since your custom application will not be unified.