Windows Smart App Control blocks the unsigned binary on first launch, causing `spawnSync ... UNKNOWN`
- Dominant language
- Rust
- Stars
- 26
- Forks
- 6
- Avg merge
- 1h 13m
- Merged PRs (30d)
- 384
Description
## What happened?
On Windows 11 with Smart App Control (SAC) enabled, installing Pentect 0.0.81 globally succeeds, but the first `pentect` launch fails with:
```text
C:\Users\>bun i -g pentect
bun add v1.4.0
installed pentect@0.0.81 with binaries:
- pentect
1 package installed
C:\Users\>pentect
pentect: spawnSync C:\Users\\AppData\Local\Pentect\npm\0.0.81\pentect.exe UNKNOWN
```
This is not caused by Bun's shim, PATH, CPU architecture, or a corrupt download. Windows Code Integrity logs confirm that SAC rejected the unsigned native executable.
## Environment
- Pentect: `0.0.81`
- Windows 11 Pro 25H2, build `26200.9168`, x64
- Smart App Control: `On`
- Microsoft Defender real-time protection: `On`
- Bun: `1.4.0`
- Node.js: `24.19.0`
## Steps to reproduce
1. On Windows with SAC enabled, run `bun i -g pentect`.
2. Run `pentect` for the first time.
3. The npm launcher downloads the Windows native binary from the GitHub release and immediately starts it with `spawnSync`.
4. The launch fails with the `UNKNOWN` error shown above.
On this machine, the same file started successfully after Defender's cloud reputation evaluation completed. The issue therefore stops reproducing on an endpoint once reputation for that exact hash is cached, but can recur for each new unsigned release hash.
## Diagnostic evidence
The `Microsoft-Windows-CodeIntegrity/Operational` log contains events matching the exact failure time:
- Event ID: `3077`, with `3033` and `3118` at the same time
- Policy: `VerifiedAndReputableDesktop`
- Policy GUID: `{0283ac0f-fff1-49ae-ada1-8a933130cad6}`
- Status: `0xc0e90002` (System Integrity Policy Violation)
- Target: `%LOCALAPPDATA%\Pentect\npm\0.0.81\pentect.exe`
- Publisher: unknown; signature count: 0
- Event 3118: a Defender cloud reputation call was requested
- A later Defender Event 2010 reports that additional intelligence was acquired
Binary inspection:
```text
Get-AuthenticodeSignature: NotSigned
PE machine: 0x8664 (AMD64)
SHA-256: A4E633D6B8560EADDAA81DE4D2CDE01599196B4DFD59B071DF7D96D661F6E3FD
```
The SHA-256 digest matches the official v0.0.81 release asset. The file has no `Zone.Identifier`, so this is not a block that `Unblock-File` can resolve. After the cloud reputation check completed, the same npm launcher and native binary ran `pentect --version` repeatedly with exit code 0.
## Impact
- A valid installation appears corrupt, leading users to suspect Bun, npm, or PATH.
- The `UNKNOWN` message gives no indication that Windows security policy rejected the process.
- Pentect is itself a security boundary, so disabling SAC/Defender or adding broad exclusions is not an appropriate workaround.
- Each unsigned release produces a new hash, so endpoint reputation caching is not a durable solution.
## Expected behavior and proposed direction
The durable fix is to Authenticode-sign the Windows release executable with a certificate issued by a trusted CA and add a trusted timestamp.
The release pipeline should perform these steps in this order:
1. Build the Windows executable.
2. Apply the Authenticode signature and timestamp.
3. Generate `.gz`, SHA-256, and attestations from the signed executable.
4. Verify that `Get-AuthenticodeSignature` reports `Valid` for the published asset.
As a secondary mitigation, the npm launcher could use a bounded retry when a just-downloaded Windows executable fails to spawn with `UNKNOWN`, followed by an actionable message mentioning SAC/code signing if the failure persists. A retry is not a durable substitute for signing.
## Acceptance criteria
- [ ] The published Windows executable has an Authenticode status of `Valid`.
- [ ] A fresh installation launches successfully on a clean Windows endpoint with SAC enabled.
- [ ] If policy still rejects the executable, the launcher reports an actionable cause instead of only `spawnSync ... UNKNOWN`.
- [ ] The gzip asset, checksum, and attestation all correspond to the final signed executable.
- [ ] Users are not required to disable SAC/Defender or add broad exclusions.
## References
- [Pentect v0.0.81](https://github.com/EdamAme-x/pentect/releases/tag/v0.0.81)
- [npm installer](https://github.com/EdamAme-x/pentect/blob/v0.0.81/packaging/npm/install.js)
- [npm launcher](https://github.com/EdamAme-x/pentect/blob/v0.0.81/packaging/npm/bin/pentect.js)
- [Microsoft: Smart App Control overview](https://learn.microsoft.com/windows/apps/develop/smart-app-control/overview)
- [Microsoft: Code signing for Smart App Control](https://learn.microsoft.com/windows/apps/develop/smart-app-control/code-signing-for-smart-app-control)
Contributor guide
Research direction
Start by tracing how the Windows executable is built and published, then inspect packaging/npm/install.js and packaging/npm/bin/pentect.js. Check how signing, timestamps, gzip assets, checksums, and attestations are handled. Done means the published executable reports Valid with Get-AuthenticodeSignature, launches on a clean SAC-enabled endpoint, and failures provide an actionable message.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- bun, javascript, rust
- Domain
- release, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100