diff --git a/.gitignore b/.gitignore
index cf35973..990fde9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,6 +34,11 @@ Installer/Output/
*.iss.bak
*.exe.sig
+# Windows App Runtime redistributable — exceeds GitHub's 100 MB limit.
+# Download before building the installer:
+# .\Installer\Download-Runtime.ps1
+Installer/WindowsAppRuntimeInstall-x64.exe
+
# ─── MSIX / AppPackages ───────────────────────────────────────────────────────
AppPackages/
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2c32c64..476c3ee 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+## [1.0.9] - 2026-05-04
+
+### Fixed
+- **HVCI crash (STATUS_INVALID_IMAGE_HASH)**: PassKey v1.0.7 and v1.0.8 crashed silently on
+ every PC with Hypervisor-Protected Code Integrity (HVCI) enabled — the majority of modern
+ Windows 11 systems with TPM. Windows Code Integrity rejected the NuGet-bundled
+ `Microsoft.UI.Xaml.dll` with exception code `0xc000027b` because NuGet copies are not
+ registered in the Windows system catalog. No window ever appeared and no crash log was
+ written (the exception is a native SEH fault that bypasses .NET `catch`).
+
+ The fix removes `WindowsAppSDKSelfContained` from the build (the publish folder no longer
+ contains `Microsoft.UI.Xaml.dll`), adds an explicit `Bootstrap.Initialize(1.8)` call in
+ `Program.cs`, and bundles the official **Windows App Runtime 1.8** installer
+ (`WindowsAppRuntimeInstall-x64.exe`) inside the PassKey installer. The runtime is installed
+ silently during setup; its DLLs are fully trusted by Windows Code Integrity.
+
+ A user-visible error dialog (Win32 `MessageBoxW`) is shown on the rare occasion that
+ `Bootstrap.Initialize` fails (e.g. corrupt runtime installation), replacing the previous
+ silent disappearance.
+
## [1.0.8] - 2026-05-04
### Fixed
@@ -128,7 +148,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Giuseppe Imperato** — concept, design, product decisions
- **[Claude](https://www.anthropic.com/claude) by Anthropic** — architecture, implementation, documentation
-[Unreleased]: https://github.com/pexatar/PassKey/compare/v1.0.8...HEAD
+[Unreleased]: https://github.com/pexatar/PassKey/compare/v1.0.9...HEAD
+[1.0.9]: https://github.com/pexatar/PassKey/compare/v1.0.8...v1.0.9
[1.0.8]: https://github.com/pexatar/PassKey/compare/v1.0.7...v1.0.8
[1.0.7]: https://github.com/pexatar/PassKey/compare/v1.0.6...v1.0.7
[1.0.6]: https://github.com/pexatar/PassKey/compare/v1.0.5...v1.0.6
diff --git a/Installer/Download-Runtime.ps1 b/Installer/Download-Runtime.ps1
new file mode 100644
index 0000000..1c229b2
--- /dev/null
+++ b/Installer/Download-Runtime.ps1
@@ -0,0 +1,19 @@
+# Download-Runtime.ps1
+# Downloads the Windows App Runtime 1.8.260101001 redistributable required to
+# build the PassKey installer. The file is excluded from git (> 100 MB limit).
+#
+# Usage: .\Installer\Download-Runtime.ps1
+# Run once before building the installer with Inno Setup.
+
+$url = "https://aka.ms/windowsappsdk/1.8/1.8.260101001/windowsappruntimeinstall-x64.exe"
+$output = Join-Path $PSScriptRoot "WindowsAppRuntimeInstall-x64.exe"
+
+if (Test-Path $output) {
+ Write-Host "Already present: $output" -ForegroundColor Green
+ exit 0
+}
+
+Write-Host "Downloading Windows App Runtime 1.8.260101001..." -ForegroundColor Cyan
+Invoke-WebRequest -Uri $url -OutFile $output -UseBasicParsing
+$sizeMB = [math]::Round((Get-Item $output).Length / 1MB, 1)
+Write-Host "Done — $sizeMB MB saved to: $output" -ForegroundColor Green
diff --git a/Installer/PassKey.iss b/Installer/PassKey.iss
index 6663869..26460f6 100644
--- a/Installer/PassKey.iss
+++ b/Installer/PassKey.iss
@@ -4,8 +4,8 @@
[Setup]
AppId={{A7F3C2D1-8E4B-4F9A-B6D5-3C1E7A2F0D84}
AppName=PassKey
-AppVersion=1.0.8
-AppVerName=PassKey 1.0.8
+AppVersion=1.0.9
+AppVerName=PassKey 1.0.9
AppPublisher=Giuseppe Imperato
AppPublisherURL=https://github.com/pexatar/PassKey
AppSupportURL=https://github.com/pexatar/PassKey/issues
@@ -38,6 +38,12 @@ Name: "portuguese"; MessagesFile: "compiler:Languages\Portuguese.isl"
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; Flags: unchecked
[Files]
+; Windows App Runtime 1.8 redistributable — installed silently before the app launches.
+; HVCI (Hypervisor-Protected Code Integrity) rejects DLLs that are not in the Windows
+; Code Integrity system catalog. The official runtime installer registers trusted, cataloged
+; DLLs; the NuGet-bundled copies (WindowsAppSDKSelfContained) do not.
+Source: "WindowsAppRuntimeInstall-x64.exe"; DestDir: "{tmp}"; Flags: ignoreversion deleteafterinstall
+
; Published self-contained output (Desktop + BrowserHost)
Source: "..\publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
@@ -59,4 +65,11 @@ Root: HKCU; Subkey: "SOFTWARE\Google\Chrome\NativeMessagingHosts\com.passkey.hos
Root: HKCU; Subkey: "SOFTWARE\Mozilla\NativeMessagingHosts\com.passkey.host"; ValueType: string; ValueData: "{app}\com.passkey.host.json"; Flags: uninsdeletevalue
[Run]
+; 1. Install Windows App Runtime 1.8 silently (waits for completion before continuing).
+; RunOnceId prevents re-running on reinstall/repair if the runtime is already present.
+Filename: "{tmp}\WindowsAppRuntimeInstall-x64.exe"; Parameters: "--quiet"; \
+ StatusMsg: "Installing Windows App Runtime 1.8..."; \
+ Flags: waituntilterminated; RunOnceId: "WinAppRuntime18"
+
+; 2. Launch PassKey after installation completes.
Filename: "{app}\PassKey.Desktop.exe"; Description: "Launch PassKey"; Flags: nowait postinstall skipifsilent
diff --git a/README.md b/README.md
index 784dcc4..e3ed0fd 100644
--- a/README.md
+++ b/README.md
@@ -57,8 +57,8 @@ PassKey stores your passwords, credit cards, identities, and secure notes in a l
| Version | Platform | Type |
|---------|----------|------|
-| [v1.0.8](https://github.com/pexatar/PassKey/releases/tag/v1.0.8) | Windows x64 | Installer EXE |
-| [v1.0.8](https://github.com/pexatar/PassKey/releases/tag/v1.0.8) | Windows x64 | Portable ZIP |
+| [v1.0.9](https://github.com/pexatar/PassKey/releases/tag/v1.0.9) | Windows x64 | Installer EXE |
+| [v1.0.9](https://github.com/pexatar/PassKey/releases/tag/v1.0.9) | Windows x64 | Portable ZIP |
> **Requirements:** Windows 10 version 1809 (build 17763) or later, x64 processor.
> No .NET runtime required — PassKey is fully self-contained.
diff --git a/src/PassKey.Desktop/PassKey.Desktop.csproj b/src/PassKey.Desktop/PassKey.Desktop.csproj
index 0ed73e7..fe907cb 100644
--- a/src/PassKey.Desktop/PassKey.Desktop.csproj
+++ b/src/PassKey.Desktop/PassKey.Desktop.csproj
@@ -12,12 +12,11 @@
true
true
None
- true
false
PassKey.Desktop
- 1.0.8
- 1.0.8.0
- 1.0.8.0
+ 1.0.9
+ 1.0.9.0
+ 1.0.9.0
app.manifest
Assets\PassKey.ico
DISABLE_XAML_GENERATED_MAIN
diff --git a/src/PassKey.Desktop/Program.cs b/src/PassKey.Desktop/Program.cs
index 8882d9f..82b575b 100644
--- a/src/PassKey.Desktop/Program.cs
+++ b/src/PassKey.Desktop/Program.cs
@@ -1,4 +1,5 @@
using System.Reflection;
+using System.Runtime.InteropServices;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
@@ -61,6 +62,31 @@ public static void Main(string[] args)
// ── App startup ──────────────────────────────────────────────────────
// Note: ApplySavedLanguage() is called inside App() constructor before
// InitializeComponent(), following the official Microsoft docs pattern.
+
+ // ── Windows App Runtime bootstrap ────────────────────────────────────
+ // Required for unpackaged apps with a custom Main (DISABLE_XAML_GENERATED_MAIN)
+ // when WindowsAppSDKSelfContained is NOT set. Locates and activates the
+ // system-installed Windows App Runtime 1.8 instead of NuGet-bundled copies.
+ // NuGet-bundled Microsoft.UI.Xaml.dll triggers STATUS_INVALID_IMAGE_HASH
+ // (0xc000027b) on HVCI-enabled systems because it is not in the Windows
+ // Code Integrity system catalog.
+ try
+ {
+ // 0x00010008 = (1 << 16) | 8 → minimum version 1.8
+ Microsoft.Windows.ApplicationModel.DynamicDependency.Bootstrap.Initialize(0x00010008);
+ }
+ catch (Exception ex)
+ {
+ WriteCrashLog(ex);
+ _ = MessageBoxW(
+ IntPtr.Zero,
+ "Windows App Runtime 1.8 is required but could not be initialised.\n\n" +
+ "Please reinstall PassKey to restore the required runtime.",
+ "PassKey — Missing Runtime",
+ 0x10 /* MB_ICONERROR */);
+ return;
+ }
+
try
{
WinRT.ComWrappersSupport.InitializeComWrappers();
@@ -118,4 +144,7 @@ private static void WriteCrashLog(Exception ex)
// If we can't write the log, there is nothing more we can do.
}
}
+
+ [DllImport("user32.dll", CharSet = CharSet.Unicode)]
+ private static extern int MessageBoxW(IntPtr hWnd, string text, string caption, uint type);
}