DEV Community

Cover image for How to Sign Your Python .exe With Sigstore (No Certificate Required)
Marcin Firmuga
Marcin Firmuga

Posted on

How to Sign Your Python .exe With Sigstore (No Certificate Required)

How to Sign Your Python .exe With Sigstore (No Certificate Required)

The problem: You built an open-source app. Users download your .exe. How do they know it's actually from you and hasn't been tampered with?

Traditional solution: Buy a code signing certificate. Cost: $200-400/year.

Better solution: Sigstore. Free, open source, cryptographically secure.

This is how I sign every PC_Workman release. Takes 8 minutes to set up, 30 seconds per release.


Why This Matters

Someone could:

  1. Clone your GitHub repo
  2. Add malware to your code
  3. Compile a fake .exe
  4. Distribute it claiming it's yours

Users have no way to verify authenticity without code signing.

Sigstore solves this:

  • ✅ Proves the file came from your GitHub account
  • ✅ Proves it hasn't been modified since signing
  • ✅ Provides cryptographic proof anyone can verify
  • ✅ Completely free


Want to Star? <3


What You'll Need

  • Python project compiled to .exe (PyInstaller, Nuitka, etc.)
  • GitHub account
  • 8 minutes

That's it. No credit card, no certificate purchase, no annual fees.


Step 1: Install Sigstore

pip install sigstore

That's the entire installation. Sigstore is a Python package.

Verify installation:

sigstore --version

Expected output: sigstore, version X.X.X


Step 2: Generate GitHub Token

Sigstore authenticates via GitHub OAuth, but you need a token first.

GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic)

Click "Generate new token (classic)"

Required scopes:

  • read:user
  • user:email

Token expiration: Set to "No expiration" (for ongoing releases)

Copy the token. You'll only see it once.

Store it securely:

Linux/Mac

export GITHUB_TOKEN="your_token_here"

Windows (PowerShell)

$env:GITHUB_TOKEN="your_token_here"

Or save in password manager and paste when needed.


Step 3: Sign Your .exe

Navigate to your release directory:

cd /path/to/your/releases

Sign the file:

sigstore sign \
--bundle sigstore-bundle.json \
PC_Workman_HCK.exe

Replace PC_Workman_HCK.exe with your filename.

What happens:

  1. Sigstore opens browser for GitHub OAuth
  2. You authorize the app
  3. Sigstore generates cryptographic signature
  4. Creates sigstore-bundle.json (the signature file)

Time: ~30 seconds

Output files:

  • PC_Workman_HCK.exe (unchanged)
  • sigstore-bundle.json (signature proof)

Step 4: Upload Both Files to GitHub Release

When creating a GitHub release:

Files to include:

  1. PC_Workman_HCK.exe (your executable)
  2. sigstore-bundle.json (signature)
  3. VERIFICATION.md (instructions for users - see below)

Example release structure:
PC_Workman_v1.6.4/
├── PC_Workman_HCK.exe
├── sigstore-bundle.json
├── VERIFICATION.md
└── README.md


Step 5: Create Verification Instructions for Users

Create VERIFICATION.md in your release:

Verifying This Release

Install Sigstore

pip install sigstore

Verify Signature

sigstore verify github PC_Workman_HCK.exe \
--bundle sigstore-bundle.json \
--cert-identity https://github.com/YourUsername

Expected Output

Signature verified successfully

What This Proves

  • ✅ File came from @YourUsername GitHub account
  • ✅ File hasn't been modified since signing
  • ✅ Signing happened on [date]

Replace YourUsername with your actual GitHub username.


How Verification Works (User Side)

Your users run:
sigstore verify github your-app.exe \
--bundle sigstore-bundle.json \
--cert-identity https://github.com/YourUsername

Sigstore checks:

  1. Certificate identity: Does the signature match the claimed GitHub account?
  2. Integrity: Has the file been modified since signing?
  3. Timestamp: When was this signed?

Success output:
Verified OK: PC_Workman_HCK.exe

Failure output:
Verification failed: signature invalid

No trust required. Pure cryptography.


Real-World Example: PC_Workman

Every PC_Workman release includes:

  1. The executable (PC_Workman_HCK.exe)
  2. Sigstore bundle (sigstore-bundle.json)
  3. Security report (VirusTotal scan results)
  4. Verification guide (how to verify)

My release checklist:

1. Build executable

pyinstaller main.py

2. Sign with Sigstore

sigstore sign --bundle sigstore-bundle.json dist/PC_Workman_HCK.exe

3. Scan on VirusTotal

(manual upload to virustotal.com)

4. Create GitHub release

Upload: .exe + bundle + security report

5. Update documentation

Link to verification guide

Time per release: 5-10 minutes total.


Beyond Basic Signing

Automated Signing in CI/CD

You can integrate Sigstore into GitHub Actions:
name: Release

on:
release:
types: [created]

jobs:
sign-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

  - name: Install Sigstore
    run: pip install sigstore

  - name: Sign executable
    run: |
      sigstore sign \
        --bundle sigstore-bundle.json \
        dist/your-app.exe
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  - name: Upload signed files
    uses: actions/upload-artifact@v3
    with:
      name: signed-release
      path: |
        dist/your-app.exe
        sigstore-bundle.json
Enter fullscreen mode Exit fullscreen mode

Result: Every release = automatically signed.

Adding More Trust Signals

Sigstore proves the file came from your GitHub. But how do users know YOU'RE legitimate?

1. ORCID iD (Persistent Identity)

Register at orcid.org

  • Persistent digital identity for researchers/developers
  • Link to GitHub profile
  • Proves you're a real person

2. GitHub Developer Program

Apply at github.com/developer

  • Shows commitment to open source
  • Requires public profile + active projects
  • Free membership

3. OpenSSF Best Practices Badge

Apply at bestpractices.coreinfrastructure.org

  • 60+ security criteria
  • Comprehensive security audit
  • Industry-recognized badge

Together: These create a web of trust.

Common Issues & Fixes

"GitHub OAuth failed"

Solution: Check your GitHub token has read:user and user:email scopes.

"Bundle file not found"

Solution: Make sure --bundle filename matches what you upload to releases.

"Verification failed: certificate identity mismatch"

Solution: --cert-identity must match exact GitHub URL. Use https://github.com/YourUsername, not github.com/YourUsername.

"Command not found: sigstore"

Solution: Activate the Python environment where you installed Sigstore, or install globally.

Why I Actually Did This

I was tired of people asking "how do I know this is safe?"

Not because they're paranoid. Because they're smart. Running .exe files from unknown people IS risky.

Sigstore gives users the option to verify. No blind trust required. Just math.

Setup time: 8 minutes

Per-release time: 30 seconds

Cost: $0

User confidence: Significantly improved

Worth it.

The Complete Security Stack

For PC_Workman, I combine:

  1. VirusTotal scanning (70 antivirus engines) - Part 1 article
  2. Sigstore signing (this article)
  3. CodeQL analysis (GitHub security scanning)
  4. OpenSSF Best Practices (working toward badge) - Part 3 coming soon

None of this prevents bugs. None of it proves bug-free code.

But it proves I'm serious about security and transparency.

Users can verify for themselves. That's what matters.

Try It Yourself

5-minute challenge:

  1. Install Sigstore: pip install sigstore
  2. Create a test file: echo "test" > test.txt
  3. Sign it: sigstore sign --bundle test-bundle.json test.txt
  4. Verify it: sigstore verify github test.txt --bundle test-bundle.json --cert-identity https://github.com/YourUsername

You just cryptographically signed your first file.

Now apply this to your actual releases.

Resources

Official Sigstore docs: docs.sigstore.dev

GitHub integration guide: GitHub + Sigstore

PC_Workman releases (examples): GitHub Releases

Questions? Drop them below. I'll answer every one.

About This Series

This is Part 2 of 3 in the PC_Workman Security Series:

About Me

I'm Marcin, solo developer building PC_Workman — an open-source system monitoring tool.

Built on a dying 2014 laptop during warehouse shifts in the Netherlands. 700+ hours, 4 complete rebuilds, finally shipped.

Follow my build-in-public journey:

Building in public. Documenting everything. Shipping weekly.

sigstore #python #security #opensource #buildinpublic

Top comments (0)