In tools/decrypt.ps1, archive entries were extracted via Path.Combine(targetFolder, entry.FullName). In .NET Framework, Path.Combine resolves ../ relative traversal sequences, and ignores targetFolder entirely if entry.FullName is rooted (e.g. C:\Windows\...). A crafted .zev container could write files to Startup directories without user interaction.
string targetFullPath = Path.GetFullPath(targetFolder);
if (!targetFullPath.EndsWith(Path.DirectorySeparatorChar.ToString()))
targetFullPath += Path.DirectorySeparatorChar;
foreach (var entry in archive.Entries) {
string cleanName = entry.FullName.Replace('\\', '/').TrimStart('/');
string destPath = Path.GetFullPath(Path.Combine(targetFolder, cleanName));
if (!destPath.StartsWith(targetFullPath, StringComparison.OrdinalIgnoreCase))
throw new System.Security.SecurityException("Zip-Slip detected: " + entry.FullName);
// Enforce Windows reserved device name validation
string fileNameOnly = Path.GetFileName(cleanName);
if (Regex.IsMatch(fileNameOnly, @"^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(\..*)?$", RegexOptions.IgnoreCase))
throw new System.Security.SecurityException("Reserved device name: " + entry.FullName);
}