Skip to content

Security: singhpratech/notepatra

Security

SECURITY.md

Security Policy

Reporting a vulnerability

Do not file a public GitHub issue for security bugs.

If you have found a vulnerability in Notepatra — anything from RCE in the editor, supply-chain compromise of a release artifact, an issue with the install scripts, a memory-safety bug in the C++/Rust code, or anything else that could harm a user — please report it privately:

  1. GitHub private vulnerability reporting (preferred): https://github.com/singhpratech/notepatra/security/advisories/new
  2. Email: open the GitHub profile of @singhpratech and use the contact listed there.

Please include:

  • What you found (be as specific as possible — file path, line number, version, OS)
  • Steps to reproduce
  • The impact (what an attacker could achieve)
  • A suggested fix, if you have one

I will acknowledge the report within 72 hours and keep you posted on the timeline. Coordinated disclosure is welcome — once a fix lands, you'll be credited (unless you'd rather stay anonymous).

Supported versions

Only the latest release is supported with security patches. Notepatra is pre-1.0; backporting patches to old tags is not feasible. Always upgrade to the newest release.

Version Supported
latest (main / latest tag)
anything older

Verifying a release

Every Notepatra binary is published to GitHub Releases with three independent integrity checks. Use at least one of them before running a downloaded binary.

1. SHA-256 checksums (everyone should do this)

Every release ships a SHA256SUMS file alongside the binaries.

Linux / macOS:

curl -sL -O https://github.com/singhpratech/notepatra/releases/download/v0.1.60/SHA256SUMS
curl -sL -O https://github.com/singhpratech/notepatra/releases/download/v0.1.60/notepatra-linux-x64.tar.gz
sha256sum -c SHA256SUMS --ignore-missing
# expected: notepatra-linux-x64.tar.gz: OK

If you downloaded the ARM64 Linux build, verify notepatra-linux-arm64.tar.gz the same way.

Windows PowerShell:

Invoke-WebRequest https://github.com/singhpratech/notepatra/releases/download/v0.1.60/SHA256SUMS -OutFile SHA256SUMS
Invoke-WebRequest https://github.com/singhpratech/notepatra/releases/download/v0.1.60/notepatra-windows-x64.zip -OutFile notepatra-windows-x64.zip
$expected = (Get-Content SHA256SUMS | Select-String 'notepatra-windows-x64.zip').Line.Split(' ')[0]
$actual   = (Get-FileHash notepatra-windows-x64.zip -Algorithm SHA256).Hash.ToLower()
if ($expected -ne $actual) { Write-Error 'CHECKSUM MISMATCH — DO NOT RUN' } else { 'OK' }

The install.sh and install.ps1 scripts on notepatra.org perform this check automatically and refuse to install if SHA256SUMS is unreachable or the checksum doesn't match. (This was tightened to hard-fail in v0.1.82 — prior versions silently skipped the check when SHA256SUMS returned a network error, which has been fixed.)

Per-release SHA256SUMS files live with the release artifacts at https://github.com/singhpratech/notepatra/releases/download/<tag>/SHA256SUMS. The legacy pinned copy at https://notepatra.org/SHA256SUMS.v0.1.0.txt is preserved for v0.1.0 only; all other tags are served from the GitHub Releases asset.

2. Cosign signatures (Sigstore, keyless)

Every release artifact is signed via Sigstore cosign using keyless OIDC signing — there is no long-lived signing key for me to leak. The signing identity is the GitHub Actions OIDC token of the official singhpratech/notepatra repo, and the cert is recorded in the public Rekor transparency log.

# Install cosign: https://docs.sigstore.dev/cosign/installation/
# Replace `linux-x64` with `linux-arm64` if that is the artifact you downloaded.
# Replace v0.1.82 with the actual tag you downloaded.
cosign verify-blob \
  --certificate-identity-regexp '^https://github.com/singhpratech/notepatra/\.github/workflows/.+@refs/tags/v0\.1\.82$' \
  --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
  --certificate notepatra-linux-x64.tar.gz.pem \
  --signature  notepatra-linux-x64.tar.gz.sig \
  notepatra-linux-x64.tar.gz
# expected: Verified OK

The cert-identity-regexp is pinned to a workflow path and tag. An unrelated workflow (or a workflow added by a compromised maintainer) would be rejected even if it ran in this repo. The Notepatra install.sh and install.ps1 perform this verification automatically when cosign is on PATH.

If cosign verify-blob says Verified OK, you have cryptographic proof that the binary was built by the official singhpratech/notepatra GitHub Actions workflow on a specific git commit, and the signature is recorded in a public append-only log.

3. SLSA build provenance

Every release includes an SLSA build provenance attestation generated by GitHub's actions/attest-build-provenance. This is a stronger guarantee than just a signature — it cryptographically links the binary to:

  • the git commit it was built from
  • the workflow file that built it
  • the runner environment
  • the build inputs
# Install gh CLI: https://cli.github.com
# Replace `linux-x64` with `linux-arm64` for the ARM build.
gh attestation verify notepatra-linux-x64.tar.gz --owner singhpratech
# expected: Loaded digest sha256:... for file://...
#           Verification succeeded!

What "verified" actually proves

If all three checks pass, you know:

  • The binary you downloaded is byte-for-byte the file produced by GitHub Actions for the tagged commit.
  • That commit is the public source code in this repo at that tag.
  • The build was performed by the workflow defined in .github/workflows/build.yml at that commit, in GitHub-hosted runners.

What it does not prove:

  • That the source code is bug-free (read it / audit it)
  • That the upstream Rust crates, Qt, or QScintilla are themselves bug-free
  • That GitHub itself wasn't compromised at build time (this is the floor of trust for the entire SLSA model)

Threat model and design choices

Notepatra is a local-first editor. Key choices that bound the attack surface:

Choice Why
Local AI only (Ollama) The AI model runs on your machine. No prompts ever leave your computer. There is no API key, no remote server, no telemetry.
No telemetry, no analytics, no phone-home The binary makes zero outbound network connections except: (a) Ollama on localhost, (b) git pull/push when you click those buttons, (c) the REST client tab when you explicitly send a request. Verifiable with strace, dtruss, or Process Monitor.
Plugin loading is opt-in Plugins are loaded only from ~/.config/notepatra/plugins/ (per-user, not system-wide). Plugins are unsigned native code — only install plugins from sources you trust, the same way you would for any native plugin system.
Crash recovery writes to ~/.config/notepatra/recovery/ Per-user, never to a world-writable location.
The Rust core handles all file I/O, parsing, and untrusted-input handling Rust's memory safety eliminates the buffer-overflow class of bugs in the most attack-prone code paths (file loading, search, diff, JSON/HTML/SQL parsing).
No JavaScript, no embedded browser, no Electron Notepatra has zero browser engine, so it has zero browser-engine CVEs.

Build & supply chain hardening

What the project does today:

  • ✅ Open-source release pipeline via GitHub Actions (workflow files in .github/workflows/)
  • ✅ SHA-256 checksums published with every release
  • ✅ Cosign keyless signing of every artifact (Sigstore + Rekor transparency log)
  • ✅ SLSA build provenance attestation (actions/attest-build-provenance) for every artifact
  • install.sh and install.ps1 hard-fail if SHA256SUMS is unreachable or the artifact is not listed (no silent-skip)
  • install.sh and install.ps1 run cosign verify-blob automatically when cosign is on PATH, with the cert-identity pinned to the release workflow + tag
  • ✅ Minimum-permission GITHUB_TOKEN (default_workflow_permissions: read); release job uses id-token: write only while gated by startsWith(github.ref, 'refs/tags/v')
  • ✅ Repository ruleset on main: no deletion, no force-push, required linear history, required signed commits, CodeQL (high-or-higher) required, Copilot review on push
  • ✅ Tag protection ruleset on refs/tags/v*: no deletion, no force-push, signed-tag required
  • ✅ Dependabot security updates enabled (alerts route to maintainer)
  • ✅ Secret-scanning + push-protection enabled
  • ✅ Public vulnerability disclosure path (this file + GitHub Security tab + RFC 9116 security.txt)
  • ✅ Website (notepatra.org / GitHub Pages) enforces HTTPS, ships Content-Security-Policy + X-Content-Type-Options + Referrer-Policy + Permissions-Policy meta tags, loads zero third-party JS / analytics / CDN

What the project does not do yet (honest about it):

  • ❌ Code signing on Windows (requires a paid EV certificate ~$300/year)
  • ❌ Apple notarization on macOS (requires an Apple Developer account, $99/year)
  • ❌ Pinning every GitHub Action by commit SHA — the highest-risk three (attest-build-provenance, softprops/action-gh-release, cosign-installer) are pinned; the remaining ~35 use floating major-version tags and are being swept in batches
  • ❌ Reproducible builds (bit-for-bit) — would need a deterministic build environment
  • ❌ Required PR reviews on main — Notepatra is currently a solo-maintainer project; the ruleset blocks force-push / deletion and requires signed commits, but the pull_request rule's required_approving_review_count is 0. The maintainer also retains ruleset bypass; account compromise = direct write to main. Hardware-key 2FA on the maintainer account is the mitigation
  • cargo audit gate in release-check.sh — planned; today the version pinning in rust-core/Cargo.toml is the only signal
  • ❌ DNSSEC + CAA records on notepatra.org — work in progress with the registrar
  • ❌ Per-page Subresource Integrity for images — currently low priority because no third-party JS is loaded

If any of these matter to you and you'd like to help fund or contribute the work, reach out via @singhpratech.

Hall of fame

(Empty so far — yours could be the first name here.)

There aren't any published security advisories