diff --git a/ext/installfiles/windows/ZeroTier One.aip b/ext/installfiles/windows/ZeroTier One.aip
index 49cb0a6387..0dd2764c50 100644
--- a/ext/installfiles/windows/ZeroTier One.aip
+++ b/ext/installfiles/windows/ZeroTier One.aip
@@ -1,542 +1,545 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/osdep/OSUtils.cpp b/osdep/OSUtils.cpp
index 97a2e87097..25d4e8f70c 100644
--- a/osdep/OSUtils.cpp
+++ b/osdep/OSUtils.cpp
@@ -34,6 +34,8 @@
#include
#include
#include
+#include
+#include
#endif
#include "OSUtils.hpp"
@@ -265,6 +267,29 @@ void OSUtils::lockDownFile(const char* path, bool isDir)
#endif
}
+void OSUtils::secureDirectory(const char* path)
+{
+#ifdef __WINDOWS__
+ // Apply a protected (non-inheriting) DACL so standard users cannot create or modify
+ // files in this directory: SYSTEM full, Administrators modify, Everyone read+execute,
+ // inheritable to child files/subdirs. PROTECTED_DACL_SECURITY_INFORMATION strips any
+ // inherited ACE (e.g. the ProgramData 'Users:(create files)' grant that enables the
+ // DLL-planting LPE). Re-asserted on every service start, so it remediates upgrades and
+ // pre-existing installs the MSI does not re-secure. Mirrors the installer One_Dir SDDL.
+ PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR)0;
+ if (ConvertStringSecurityDescriptorToSecurityDescriptorA("D:PAR(A;OICI;FA;;;SY)(A;OICI;0x1301bf;;;BA)(A;OICI;0x1200a9;;;WD)", SDDL_REVISION_1, &sd, (PULONG)0)) {
+ BOOL daclPresent = FALSE, daclDefaulted = FALSE;
+ PACL dacl = (PACL)0;
+ if ((GetSecurityDescriptorDacl(sd, &daclPresent, &dacl, &daclDefaulted)) && (daclPresent)) {
+ SetNamedSecurityInfoA((LPSTR)path, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, (PSID)0, (PSID)0, dacl, (PACL)0);
+ }
+ LocalFree(sd);
+ }
+#else
+ (void)path;
+#endif
+}
+
uint64_t OSUtils::getLastModified(const char* path)
{
struct stat s;
diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp
index 5c3eb7f33a..5cd6b4cef9 100644
--- a/osdep/OSUtils.hpp
+++ b/osdep/OSUtils.hpp
@@ -178,6 +178,18 @@ class OSUtils {
*/
static void lockDownFile(const char* path, bool isDir);
+ /**
+ * Apply a hardened, protected ACL to a directory (Windows; no-op elsewhere)
+ *
+ * Sets an explicit, non-inheriting DACL granting full control to SYSTEM, modify to
+ * Administrators, and read+execute to Everyone. Re-asserting this at service startup
+ * closes the DLL-planting privilege-escalation class on hosts where the installer did
+ * not (re)secure a pre-existing working directory.
+ *
+ * @param path Directory to secure
+ */
+ static void secureDirectory(const char* path);
+
/**
* Get file last modification time
*
diff --git a/service/OneService.cpp b/service/OneService.cpp
index d5d086058e..fdb1520d8a 100644
--- a/service/OneService.cpp
+++ b/service/OneService.cpp
@@ -1114,6 +1114,10 @@ class OneServiceImpl : public OneService {
virtual ReasonForTermination run()
{
try {
+ // Re-assert the protected working-directory ACL on every start. The MSI does not
+ // re-secure a pre-existing directory, so a host upgraded from a vulnerable build
+ // would otherwise keep the bad ACL. No-op on non-Windows.
+ OSUtils::secureDirectory(_homePath.c_str());
{
const std::string authTokenPath(_homePath + ZT_PATH_SEPARATOR_S "authtoken.secret");
if (! OSUtils::readFile(authTokenPath.c_str(), _authToken)) {