-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Description
Summary
A DLL side-loading vulnerability affects all Windows builds of Go when running on non-English Windows. When the
standard library time package initializes the local time zone (time.initLocal), it can trigger Windows to call
RegLoadMUIStringW (via GetMUIStringValue) without specifying a search directory on the first call. As a result,
Windows may attempt to load tzres.dll from the application's current working directory before falling back to
System32. This creates a DLL side-loading risk on machines with non-English locales.
Why tzres.dll is loaded
time.initLocallazily initializes localtime.Locationdata.- If a time zone abbreviation is not found in Go's internal map on non-English systems, the runtime calls into Windows
to retrieve a localized string (viaGetMUIStringValue). - The underlying Windows call (
RegLoadMUIStringW) is invoked first without a directory parameter, which leads
Windows to look fortzres.dllin the current working directory. - Only on a subsequent attempt does Windows use the System32 directory, so the initial nil-directory call is the root
cause of the observable attempt to loadtzres.dllfrom the CWD.
Reproduction
- Use a non-English Windows installation (e.g., I used Turkish Windows 10).
- Run a minimal Go program that touches
time.Local. For example, this one line triggers the behavior:println(time.Local.String())
- Observe the behavior with Sysinternals Process Monitor.
Note about attempted mitigations (no effect)
The following Windows API calls, when invoked early, do not prevent the observed RegLoadMUIStringW behavior and
therefore do not stop tzres.dll being probed in the CWD:
- SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32)
- SetDllDirectoryW(L"")
- SetSearchPathMode(BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT)
Workaround Used
As a temporary mitigation in our environment, we used Go's -overlay build feature to override the GetMUIStringValue
function. This allowed us to patch the behavior at build time and avoid the vulnerable DLL load sequence without
modifying upstream Go sources.
Note: The Go Security team has requested that this report be tracked as a public issue.