Windows Signing & Metadata
Add PE metadata and Authenticode signatures to Windows executables.
Overview
Hakobu can inject version metadata into Windows PE executables and sign them with Authenticode. Signed executables display your publisher name in Windows SmartScreen and UAC dialogs instead of "Unknown Publisher."
PE Metadata Injection
Windows executables have a VERSIONINFO resource that stores product name, version, company, description, and icon. Hakobu injects these using resedit, a pure-JS PE resource editor that works cross-platform -- you can set Windows metadata from macOS or Linux.
Configure via package.json
{
"hakobu": {
"metadata": {
"productName": "My Application",
"fileDescription": "My App does amazing things",
"companyName": "ACME Corporation",
"legalCopyright": "Copyright 2026 ACME Corporation",
"fileVersion": "1.2.3",
"icon": "assets/app.ico"
}
}
}Configure via CLI flags
hakobu . --target node24-win-x64 --output dist/my-app.exe \
--product-name "My Application" \
--file-description "My App does amazing things" \
--company-name "ACME Corporation" \
--file-version 1.2.3 \
--icon assets/app.icoCLI flags override package.json configuration.
Supported Fields
| Field | CLI Flag | package.json Key | PE Resource |
|---|---|---|---|
| Product name | --product-name | metadata.productName | ProductName |
| File description | --file-description | metadata.fileDescription | FileDescription |
| Company name | --company-name | metadata.companyName | CompanyName |
| Copyright | (config only) | metadata.legalCopyright | LegalCopyright |
| File version | --file-version | metadata.fileVersion | FileVersion |
| Product version | --product-version | metadata.productVersion | ProductVersion |
| Icon | --icon | metadata.icon | Application icon |
Version Format
Versions are dot-separated with up to 4 parts: MAJOR.MINOR.PATCH.BUILD. Missing parts default to 0:
1.2.3 → 1.2.3.0
1.0 → 1.0.0.0
2.1.0.42 → 2.1.0.42Icon Requirements
The icon must be a Windows .ico file. PNG, JPEG, and SVG are not supported directly. Multi-resolution .ico files are recommended (16x16, 32x32, 48x48, 256x256).
# Convert with ImageMagick
magick convert icon.png -resize 256x256 icon.icoPE metadata is Windows-only. macOS uses .app bundles with Info.plist, and Linux ELF executables have no standard metadata format. These flags are ignored for non-Windows targets.
Authenticode Signing
Signing Tiers
| Tier | What Happens | When to Use |
|---|---|---|
| Unsigned (default) | No signing -- SmartScreen may warn "Unknown Publisher" | Local development, internal use |
| Self-signed | Signed with a self-issued certificate -- SmartScreen still warns | Testing the signing pipeline |
| Authenticode (OV/EV) | Signed with a trusted CA certificate | Public distribution |
OV certificates build SmartScreen reputation over time. EV certificates are trusted immediately with no reputation period.
Quick Start
Obtain a code signing certificate
You need an Authenticode certificate from a trusted CA in PKCS#12 format (.pfx or .p12):
| Type | SmartScreen Behavior | Cost |
|---|---|---|
| OV (Organization Validation) | Builds reputation over time | ~$200--400/year |
| EV (Extended Validation) | Immediate trust | ~$400--700/year |
For open source projects, SignPath Foundation offers free EV signing for qualifying projects.
Export your certificate as PFX
If you need to export from an existing certificate:
$cert = Get-ChildItem Cert:\CurrentUser\My\THUMBPRINT
$password = ConvertTo-SecureString -String "export-password" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath cert.pfx -Password $passwordOr from a CA-issued .crt + .key:
openssl pkcs12 -export -out cert.pfx \
-inkey private.key -in certificate.crt -certfile ca-chain.crtInstall a signing tool
On Windows (GitHub Actions windows-latest): signtool.exe is pre-installed via the Windows SDK.
On macOS or Linux (cross-signing):
# macOS
brew install osslsigncode
# Ubuntu/Debian
sudo apt install osslsigncodeBoth tools produce identical Authenticode signatures.
Sign the executable
Pass your certificate via the --win-cert flag or environment variable:
hakobu ./my-app --target node24-win-x64 --output ./dist/app.exe \
--win-cert ./certs/my-cert.pfx --win-cert-password "secret"Or use environment variables:
export HAKOBU_WIN_CERT="./certs/my-cert.pfx"
export HAKOBU_WIN_CERT_PASSWORD="secret"
hakobu ./my-app --target node24-win-x64 --output ./dist/app.exePipeline Order
Hakobu handles the ordering of metadata injection and signing automatically:
package → inject PE metadata → sign (Authenticode)Metadata must be injected before signing because the signature covers the entire file including resources. You can combine both in a single command:
hakobu . --target node24-win-x64 \
--product-name "My App" --file-version 1.0.0 \
--win-cert cert.pfx --win-cert-password "secret"Environment Variables
| Variable | Required | Description |
|---|---|---|
HAKOBU_WIN_CERT | Yes (for signing) | Path to .pfx/.p12 certificate file |
HAKOBU_WIN_CERT_PASSWORD | If cert is password-protected | Certificate password |
HAKOBU_WIN_TIMESTAMP_URL | No | Timestamp server (default: http://timestamp.digicert.com) |
CLI Flags
| Flag | Description |
|---|---|
--win-cert <path> | Path to .pfx/.p12 certificate (overrides HAKOBU_WIN_CERT) |
--win-cert-password <pw> | Certificate password (overrides HAKOBU_WIN_CERT_PASSWORD) |
Behavior When Credentials Are Absent
| Scenario | Behavior |
|---|---|
No HAKOBU_WIN_CERT and no --win-cert | Unsigned executable (default) |
| Certificate set but signing tool missing | Error with instructions to install signtool or osslsigncode |
| Certificate set but wrong password | Error from the signing tool with diagnostic message |
Non-Windows target with --win-cert | Flag is ignored (Authenticode is Windows-only) |
CI/CD Setup
Store your certificate as a base64-encoded GitHub secret:
base64 -i cert.pfx | tr -d '\n' > cert-base64.txt
# Copy contents to the WIN_CERT_BASE64 repository secretSigning on Windows runners
- name: Decode signing certificate
if: runner.os == 'Windows'
run: |
echo "${{ secrets.WIN_CERT_BASE64 }}" > cert-base64.txt
certutil -decode cert-base64.txt cert.pfx
del cert-base64.txt
shell: cmd
- name: Package and sign
if: runner.os == 'Windows'
env:
HAKOBU_WIN_CERT: cert.pfx
HAKOBU_WIN_CERT_PASSWORD: ${{ secrets.WIN_CERT_PASSWORD }}
run: npx hakobu ./my-app --target node24-win-x64 --output ./dist/app.exe
- name: Clean up certificate
if: always() && runner.os == 'Windows'
run: del cert.pfx
shell: cmdCross-signing from macOS or Linux
- name: Install osslsigncode
run: |
if [[ "$RUNNER_OS" == "macOS" ]]; then
brew install osslsigncode
else
sudo apt-get install -y osslsigncode
fi
- name: Decode certificate
run: echo "${{ secrets.WIN_CERT_BASE64 }}" | base64 -d > cert.pfx
- name: Package and sign
env:
HAKOBU_WIN_CERT: cert.pfx
HAKOBU_WIN_CERT_PASSWORD: ${{ secrets.WIN_CERT_PASSWORD }}
run: npx hakobu ./my-app --target node24-win-x64 --output ./dist/app.exe
- name: Clean up
if: always()
run: rm -f cert.pfxVerifying a Signed Executable
Get-AuthenticodeSignature .\app.exe
# Or with signtool
signtool verify /pa /v .\app.exeOn macOS or Linux with osslsigncode:
osslsigncode verify -in app.exeTroubleshooting
"SignTool Error: No certificates were found"
The .pfx file doesn't contain a valid code signing certificate, or the password is wrong. Re-export and verify:
signtool sign /f cert.pfx /p "password" /fd SHA256 test.exeSmartScreen still shows "Unknown Publisher"
OV certificates need to build reputation over time. Sign consistently and the warning will disappear. EV certificates are trusted immediately. Ensure timestamps are included -- unsigned timestamps cause warnings after certificate expiry.
Metadata not showing in file properties
Right-click the .exe, then select Properties and open the Details tab. Ensure the target is win (metadata is Windows-only) and that fields are spelled correctly in the configuration.