VYPR
High severity7.9NVD Advisory· Published Mar 24, 2024· Updated Apr 15, 2026

CVE-2024-29188

CVE-2024-29188

Description

WiX toolset lets developers create installers for Windows Installer, the Windows installation engine. The custom action behind WiX's RemoveFolderEx functionality could allow a standard user to delete protected directories. RemoveFolderEx deletes an entire directory tree during installation or uninstallation. It does so by recursing every subdirectory starting at a specified directory and adding each subdirectory to the list of directories Windows Installer should delete. If the setup author instructed RemoveFolderEx to delete a per-user folder from a per-machine installer, an attacker could create a directory junction in that per-user folder pointing to a per-machine, protected directory. Windows Installer, when executing the per-machine installer after approval by an administrator, would delete the target of the directory junction. This vulnerability is fixed in 3.14.1 and 4.0.5.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
wixNuGet
< 3.14.13.14.1
wixNuGet
>= 4.0.0, < 4.0.54.0.5
WixToolset.Util.wixextNuGet
< 4.0.54.0.5

Patches

2
2e5960b57588

Don't follow junctions when recursing directories.

https://github.com/wixtoolset/wixRob MenschingMar 22, 2024via ghsa
2 files changed · +13 3
  • src/dtf/SfxCA/SfxUtil.cpp+3 1 modified
    @@ -93,7 +93,9 @@ bool DeleteDirectory(const wchar_t* szDir)
                     StringCchCopy(szPath + cchDir + 1, cchPathBuf - (cchDir + 1), fd.cFileName);
                     if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
                     {
    -                        if (wcscmp(fd.cFileName, L".") != 0 && wcscmp(fd.cFileName, L"..") != 0)
    +                        if (wcscmp(fd.cFileName, L".") != 0
    +                            && wcscmp(fd.cFileName, L"..") != 0
    +                            && ((fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0))
                             {
                                     DeleteDirectory(szPath);
                             }
    
  • src/ext/Util/ca/RemoveFoldersEx.cpp+10 2 modified
    @@ -38,6 +38,14 @@ static HRESULT RecursePath(
         }
     #endif
     
    +    // Do NOT follow junctions.
    +    DWORD dwAttributes = ::GetFileAttributesW(wzPath);
    +    if (dwAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
    +    {
    +        WcaLog(LOGMSG_STANDARD, "Path is a junction; skipping: %ls", wzPath);
    +        ExitFunction();
    +    }
    +
         // First recurse down to all the child directories.
         hr = StrAllocFormatted(&sczSearch, L"%s*", wzPath);
         ExitOnFailure(hr, "Failed to allocate file search string in path: %S", wzPath);
    @@ -210,10 +218,10 @@ extern "C" UINT WINAPI WixRemoveFoldersEx(
     
             hr = PathExpand(&sczExpandedPath, sczPath, PATH_EXPAND_ENVIRONMENT);
             ExitOnFailure(hr, "Failed to expand path: %S for row: %S", sczPath, sczId);
    -        
    +
             hr = PathBackslashTerminate(&sczExpandedPath);
             ExitOnFailure(hr, "Failed to backslash-terminate path: %S", sczExpandedPath);
    -    
    +
             WcaLog(LOGMSG_STANDARD, "Recursing path: %S for row: %S.", sczExpandedPath, sczId);
             hr = RecursePath(sczExpandedPath, sczId, sczComponent, sczProperty, iMode, f64BitComponent, &dwCounter, &hTable, &hColumns);
             ExitOnFailure(hr, "Failed while navigating path: %S for row: %S", sczPath, sczId);
    
93eeb5f68357

Don't follow junctions when recursing directories.

https://github.com/wixtoolset/wix3Bob ArnsonFeb 10, 2024via ghsa
2 files changed · +13 3
  • src/DTF/Tools/SfxCA/SfxUtil.cpp+3 1 modified
    @@ -93,7 +93,9 @@ bool DeleteDirectory(const wchar_t* szDir)
                     StringCchCopy(szPath + cchDir + 1, cchPathBuf - (cchDir + 1), fd.cFileName);
                     if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
                     {
    -                        if (wcscmp(fd.cFileName, L".") != 0 && wcscmp(fd.cFileName, L"..") != 0)
    +                        if (wcscmp(fd.cFileName, L".") != 0
    +                            && wcscmp(fd.cFileName, L"..") != 0
    +                            && ((fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0))
                             {
                                     DeleteDirectory(szPath);
                             }
    
  • src/ext/ca/wixca/dll/RemoveFoldersEx.cpp+10 2 modified
    @@ -24,6 +24,14 @@ static HRESULT RecursePath(
         WIN32_FIND_DATAW wfd;
         LPWSTR sczNext = NULL;
     
    +    // Do NOT follow junctions.
    +    DWORD dwAttributes = ::GetFileAttributesW(wzPath);
    +    if (dwAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
    +    {
    +        WcaLog(LOGMSG_STANDARD, "Path is a junction; skipping: %ls", wzPath);
    +        ExitFunction();
    +    }
    +
         // First recurse down to all the child directories.
         hr = StrAllocFormatted(&sczSearch, L"%s*", wzPath);
         ExitOnFailure1(hr, "Failed to allocate file search string in path: %S", wzPath);
    @@ -159,10 +167,10 @@ extern "C" UINT WINAPI WixRemoveFoldersEx(
     
             hr = PathExpand(&sczExpandedPath, sczPath, PATH_EXPAND_ENVIRONMENT);
             ExitOnFailure2(hr, "Failed to expand path: %S for row: %S", sczPath, sczId);
    -        
    +
             hr = PathBackslashTerminate(&sczExpandedPath);
             ExitOnFailure1(hr, "Failed to backslash-terminate path: %S", sczExpandedPath);
    -    
    +
             WcaLog(LOGMSG_STANDARD, "Recursing path: %S for row: %S.", sczExpandedPath, sczId);
             hr = RecursePath(sczExpandedPath, sczId, sczComponent, sczProperty, iMode, &dwCounter, &hTable, &hColumns);
             ExitOnFailure2(hr, "Failed while navigating path: %S for row: %S", sczPath, sczId);
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.