Security

The controls actually in the product.

This page describes the security controls that are in code, not a marketing claim about the product. Every item below maps to a file or a header in the running deployment. The technical policy is in SECURITY.md.

Supported versions

Only the most recent public release receives security fixes.

SurfaceVersionStatus
Web applicationKingfisher 1.5.5Current. Served at kingfisherchess.app from every push to master.
macOS applicationKingfisher 1.5.5Apple Silicon DMG, signed with Developer ID and notarised by Apple; opens with a double-click.

Older release candidates are not patched. If a regression is reported against one, the answer is to upgrade.

Browser / web application

  • Content Security Policy — vercel.json ships a strict CSP with default-src self, no third-party script-src, frame-ancestors none, base-uri self, object-src none. The only script-src allowances are self, wasm-unsafe-eval (Stockfish WebAssembly) and unsafe-inline (no scripts are inlined; this allowance is retained for Next.js style attributes and does not allow arbitrary inline JavaScript).
  • Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: credentialless are sent on every response, which is what enables SharedArrayBuffer for the Stockfish multi-threaded build.
  • HSTS with max-age=31536000; includeSubDomains; preload and a Referrer-Policy: strict-origin-when-cross-origin header on every response.
  • Permissions-Policy disables camera, microphone, geolocation and interest-cohort (FLoC) at the document level.
  • Remote origins the application calls are named in connect-src: the application's own host, the GitHub Pages data mirror, Lichess, Chess.com and the desktop companion's loopback range. The policy also allows https:, because two calls choose their host at runtime — the full-network browser engine is fetched from the address its manifest records with a pinned SHA-256, and a user-configured assistant endpoint is whatever you typed — so it does not refuse other HTTPS hosts; the application's own code makes no other call. Scripts, styles, frames and objects are restricted to the origin regardless.
  • The Mac application’s window only shows Kingfisher. It never navigates away from the server the shell started: a link anywhere else is opened in your own browser, and only when it is an https: address; the one navigation that comes back is the Lichess sign-in callback. See desktop/src/main.mjs. In a browser, a link is an ordinary link; there is no outbound allow-list.
  • Downloaded data is verified. Every reference-pack chunk and every managed engine binary is checked against a SHA-256 recorded in the manifest before it is used; a mismatch is reported, never silently accepted. See src/reference/install.ts, companion/src/managed-engines.mjs and THIRD_PARTY_DATA.md.
  • Decompression bounds — every decompression path uses DecompressionStream with an explicit byte budget and rejects a chunk whose decompressed size exceeds the manifests record.
  • IndexedDB streaming cache — the explorer caches shards in IndexedDB with a byte budget and a TTL; cached bytes are re-verified against the manifest before they are reused.
  • Backup portability — backups are portable JSON with the same schema-versioned envelope as persistence; see docs/deployment.md.

macOS application

  • The desktop shell is Electron with contextIsolation: true, nodeIntegration: false, sandbox: true for the renderer, and a preload that exposes a typed bridge. The bridge returns null in a browser, so the same application is safe to serve over a public origin.
  • The companion’s loopback server authenticates every request except /health with a pairing token the shell mints in memory on each launch and never writes to disk; the shell and the companion are the only two processes that ever hold it. Cross-origin requests are refused by CORS.
  • The application is signed with a Developer ID Application certificate with the Hardened Runtime, notarised by Apple, and stapled; the build refuses to sign a bundle missing any required runtime file and launches the notarised application before it makes a disk image.
  • Native engines are not sandboxed. They run with the user's own operating-system permissions, and a settings panel checkbox is the only thing that prevents them from being launched. This is documented in the Settings → Engine dialog and in AGENTS.md. Do not describe managed engines as sandboxed.
  • The window cannot open a file that was not chosen in a dialog or dropped on the window; there is no readFile(path) on the bridge.
  • The shell holds no chess state. A desktop feature that needs a second copy of the board, the move tree, the engine session or the query is a bug in the arrangement, not a feature of it.

What the product deliberately does not do

  • No sync without an account. Signed out, studies, repertoire, training, notes and preferences stay in one browser profile, and the way to move them is Settings → Database → Export backup and restore on the other side. Signed in to the optional account, they sync through a database whose Row Level Security admits only their owner. Secrets never sync, and nor do imported game collections — except My games, on a device where you switch that on.
  • Page views and load times only, from this origin. The website counts page views with Vercel Web Analytics and page load timings with Vercel Speed Insights, served from /_vercel/ on this origin — no cookie, no identifier on the device, query strings stripped. No other analytics, no error-reporting service, no third-party script: the CSP is 'self' and would refuse one. The Mac application loads none of it.
  • No advertising cookies, no advertising scripts. The web build does not set any cookie; what state the application needs is held in localStorage and IndexedDB, scoped to the origin.
  • No background update. The macOS application asks the release feed when you choose Kingfisher → Check for Updates…, and once, quietly, after launch — a look that shows nothing and downloads nothing. It installs an update only when you click Install Update; the download is verified against Kingfisher’s signing key and your work is saved before the application is replaced. The web build is whatever is currently deployed; if a fix is urgent, a manual refresh picks it up.

How to report a vulnerability

Do not open a public GitHub issue, discussion, tweet or forum post for a security problem. Public issues are indexed by search engines and will be read by every attacker in the world before a fix is in the next release.

Use the private GitHub Security Advisory flow:

https://github.com/mardakurt/kingfisher/security/advisories/new

If the GitHub security flow is unavailable for any reason, open a private issue at the same repository with the word SECURITY: at the start of the title and without exploit detail in the body — the maintainer will move the conversation to the private advisory flow.

The report should include:

  • the affected version (e.g. Kingfisher 1.4.4 and the date for the web build or Kingfisher 1.4.4 and its build number for the macOS application);
  • a minimal reproduction;
  • what you observed and what you expected;
  • any workarounds you tried.

A diagnostic export from Settings → Diagnostics is safe to attach. The export never includes Lichess tokens, API keys, the companion pairing token, home-directory paths or full PGN libraries.

What to expect

The maintainer aims to:

  • acknowledge the report within seven days;
  • ship a fix in the next release, or sooner if the issue is severe;
  • publish a CVE if the report warrants one;
  • credit the reporter in the release notes (unless the reporter prefers to remain anonymous).

Out of scope

  • Engine binary vulnerabilities. Kingfisher verifies the SHA-256 of every engine it downloads against the manifest shipped in the repository, but the engines themselves are third-party and are covered by their own security policies.
  • Reference data vulnerabilities. Kingfisher verifies the SHA-256 of every chunk it downloads against the manifest shipped in the data repository.
  • Phishing, social engineering, or supply-chain attacks on the users machine. Kingfisher is local-first; the product is not a hosted service.

Non-security issues

For bugs, regressions and product questions, open an issue at the issue tracker. Paste the Settings → Diagnostics → Copy support information line so the report includes version, machine and source/engine state.