This week, I've had three separate cases where people have wondered why the CLR was assigning seemingly incorrect zone evidence to their assembly, causing their permission sets to be less than what was expected.

The quick and dirty answer is that the CLR doesn't in fact assign zones (with one small exception).  What we do is ask Windows for zone information.

If we can look at the URL of the assembly and tell that it's from the local machine, then we'll take a short cut and assign it MyComputer zone evidence directly.  However, if it's not obvious to us that the URL does belong to the local machine, we'll call urlmon via IInternetSecurityManager::MapUrlToZone in order to assign a zone.

It's relatively easy to slap together a quick function that checks what zone urlmon is assigning a URL with this API:

HRESULT MapUrlToZone(const std::wstring &wsZone, DWORD *pdwZone)
    if (pdwZone == NULL)
        return E_POINTER;

    IInternetSecurityManagerPtr pSecurityManager;
    HRESULT hr = CoInternetCreateSecurityManager(NULL, &pSecurityManager, 0);
    if (FAILED(hr))
        return hr;

    hr = pSecurityManager->MapUrlToZone(wsZone.c_str(), pdwZone, 0);
    if (FAILED(hr))
        return hr;

    return S_OK;

The DWORD can be translated to a name with the GetZoneAttributes API, checking the szDisplayName field in the ZONEATTRIBUTES structure that you're returned.  For quick reference however, MyComputer is 0, LocalIntranet 1, TrustedSites 2 and Internet 3.