Description
Summary
Released lean-ctx.exe binaries carry no Authenticode signature. On a clean Windows 11 install, Smart App Control (SAC) is enabled by default and blocks unsigned downloaded executables outright — with no "run anyway" path, unlike SmartScreen.
Reported by a community member; confirmed against release.yml.
Evidence
.github/workflows/release.yml builds and zips the Windows targets with no signing step:
line 275: Compress-Archive -Path "rust/target/${{ matrix.target }}/release/lean-ctx.exe" ...
No signtool, no certificate, no signing service. (macOS is unsigned too, but Gatekeeper still offers an override, so the user impact is lower.)
Who this affects
Smart App Control only runs on clean Windows 11 installs — an in-place upgrade from Windows 10 leaves it off, and once a user disables it, it stays off until a reinstall. So this does not affect the existing Windows install base, which evidently works.
It does affect new users on new machines — precisely at first contact, before anyone knows whether the tool is worth any effort. The README promises "Get started (30 seconds)"; these users instead hit a security block.
Workarounds (now documented in the README)
cargo install lean-ctx— builds locally; SAC treats a self-compiled binary far more leniently than a download.- WSL — lean-ctx runs as a native Linux binary there; agents reach it via
wsl lean-ctx mcp. - Disabling SAC works but is a bad trade: system-wide, permanent, reversible only by reinstalling Windows. We should not recommend it.
Fix: Azure Artifact Signing, certificate issued to Thinkery AG
Switzerland is a supported country for Public Trust certificates, and there is a Switzerland North region (https://swn.codesigning.azure.net). The service was formerly called Trusted Signing.
This is preferred over the free SignPath Foundation route for three reasons:
| SignPath Foundation | Azure Artifact Signing | |
|---|---|---|
| Certificate issued to | SignPath Foundation | Thinkery AG |
| Covers | the OSS project only | everything, including commercial builds |
| "No commercial dual-licensing on any component" clause | a real risk for us | not applicable |
| Revocation | "without notice, potentially retroactively" | ordinary contract |
| Cost | free | paid SKU (Basic/Premium) |
The decisive point: a SignPath certificate may only sign the open-source project. Any Enterprise binary, installer or Windows package for paying customers needs our own certificate anyway — doing this twice is waste. Secondarily, the Windows signature dialog then reads Thinkery AG rather than a foundation's name.
What organisation validation requires
- Legal entity name exactly as registered — Thinkery AG
- Business identifier — the CHE/UID number
- Registered business address
- Website on a company-owned domain
- Two email addresses on a company-owned domain, both able to receive external links
- Individual identity validation by an authorised representative: government ID, via AU10TIX on a phone (QR code + Microsoft Authenticator)
Plus an Azure subscription and a Microsoft Entra tenant.
Processing time: 1–20 business days, longer if Microsoft requests further documents.
Two traps worth avoiding up front
- Details must be exact. Per the docs, corrections after submission require an entirely new identity validation, which affects certificates already issued for signing.
- Public records must be current. Microsoft reconciles against the commercial register. Supporting documents must have been issued within the last 12 months and remain valid for at least two more.
CI integration
- GitHub Action:
azure/artifact-signing-action - Endpoint must match the account's region exactly — a mismatch surfaces as
403 Forbiddenwith an internalSignerSign()failure - Timestamping is mandatory, not optional: signing certificates are valid for only three days, so a signature without a timestamp stops validating almost immediately. Use
http://timestamp.acs.microsoft.com/
Caveat
Signing alone does not clear Smart App Control immediately. SAC additionally weighs reputation, which accrues with distribution. Expect a lag after the first signed release.
Fallback
If the Azure route is rejected or stalls, SignPath Foundation remains available free of charge — Apache 2.0, public repo, 3,818 stars all satisfy their published criteria. The open question there is their "no commercial dual-licensing applied to any component" clause; it should be declared in the application rather than worked around, since they can revoke retroactively. Accepting also obliges us to publish a "Code signing policy" page, define Author/Reviewer/Approver roles, and approve every release manually.
Acceptance criteria
- Windows install section documents the SAC block and both clean workarounds
- Azure subscription + Entra tenant in place for Thinkery AG
- Organisation identity validation submitted (register details verified beforehand)
- Certificate profile created in
Switzerland North - Signing step in
release.ymlviaazure/artifact-signing-action, with timestamping - Verify a signed release actually passes Smart App Control on a clean Windows 11 VM
Activity
[-]bug(windows): unsigned release binaries are blocked by Smart App Control — free Authenticode signing via SignPath[/-][+]bug(windows): unsigned release binaries are blocked by Smart App Control — sign via Azure Artifact Signing (Thinkery AG)[/+]yvgude commentedon Sep 21, 2026
Closing this: the signing work is done and proven in CI. The one remaining criterion is not something this issue can wait on, so it moves to its own ticket (see below).
What is in place
Verified against
main, not assumed:release.ymlandwindows-signing-check.ymlauthenticate via secretless OIDC usingvars.AZURE_CLIENT_ID/AZURE_TENANT_ID/AZURE_SUBSCRIPTION_ID, gated by thewindows-signingGitHub environment. The login succeeds in real runs.Switzerland North—.github/actions/windows-signing/action.ymltargetshttps://swn.codesigning.azure.net/, signing accountthinkery-signing, profileleanctx-public-trust. That is the regional endpoint this issue called for, and the403 Forbiddentrap described above does not apply.azure/artifact-signing-action@v2(SHA-pinned),file-digest: SHA256,timestamp-rfc3161: http://timestamp.acs.microsoft.com,timestamp-digest: SHA256. Mandatory timestamping was the trap flagged in this issue; it is configured, not left to chance.scripts/verify-windows-signature.ps1, so an unsigned or untimestamped artifact fails the job instead of shipping.Evidence: run 35576765725 —
Sign and verify x86_64-pc-windows-msvc: successandSign and verify x86_64-pc-windows-gnu: success. Both Windows targets, signed and verified.Landed in #1823.
What is not done, and why it does not belong here
This cannot be checked yet: no signed release has shipped. And per this issue's own caveat, SAC additionally weighs reputation that accrues with distribution — so even the first signed release may still be blocked, and a single early test would tell us little either way.
Keeping this issue open until that clears would leave it open for an unknown period on a question the signing work cannot answer. Tracked separately in #1825.
🤖 Generated with Claude Code