Releases: kldzj/sigillo
Release list
sigillo@0.17.2
This release fixes security issues. Update your instance:
npm i -g @kldzj/sigillo
npx @kldzj/sigillo@latest self-hostFixes
- Server actions and API routes check the types of their inputs before they reach a database query, so a value from the browser can only ever be looked up by its exact ID. This closes a security issue in accepting invitations.
- The login provider's sign-out sends the browser only back to its own app, never to an address a registered client names.
- Only a login from signing in with Google approves a CLI login, so a CLI login can no longer approve the next one and outlive its 30 days. A browser login from before sign-ins were told apart needs signing in again for it.
- Deleting a secret takes only a name the set routes accept, or the name of a secret that already has one from before names had rules.
- A passkey approval looks a passkey up only by an ID that is a string.
A security advisory with details follows.
sigillo@0.17.1
The Linux x64 CLI runs on every x86-64 CPU again.
Upgrading
npm i -g @kldzj/sigilloOnly the CLI changed: your instance doesn't need an update.
Fixes
- The Linux x64 binary crashed on CPUs without AVX-512, such as AMD Ryzen 5000 and most Intel desktop CPUs. CI built it for its own machine's CPU, so it died with an illegal instruction: exit code 132, or exit code 1 without a message through npm and npx. Every binary is now built for its architecture's baseline CPU. 0.16.0 and 0.17.0 have this problem on Linux x64, since whether a build used AVX-512 depended on which CI machine made it;
npx @kldzj/sigillo self-hostwasn't affected, since it runs in Node. - The npm launcher names a crash of the native binary, such as
error: sigillo was killed by SIGILL, and exits with 128 plus the signal's number, as a shell does.
sigillo@0.17.0
Workload identity for GitHub Actions and Kubernetes, warnings before tokens and trust rules expire, key rotation and encrypted backups. The docs are rewritten, and a project's tabs are simpler.
Upgrading
npm i -g @kldzj/sigillo
npx @kldzj/sigillo@latest self-host- A project's tabs changed. Tokens is now Machines, Event Log and Read Log are one History tab, and the organization's Members, which was the Access tab in every project, is in the sidebar. Bookmarks to the old pages stop working.
- New values are encrypted in a new format from the update on, bound to their environment and name. Existing values stay readable as they are; a key rotation moves them over.
- On Cloudflare's free plan, a dashboard page fails now and then with error 1102: a page often needs more than the free plan's 10 ms of CPU. Everything else works. Workers Paid, $5 a month, avoids it.
self-hostnow says so on a new deployment. ENCRYPTION_KEYmust be 32 bytes. Keys made byself-hostalways are. If you set a shorter one by hand in the Cloudflare dashboard, the instance stops decrypting after the update until you replace it.sigillo audit verifyon a protected environment asks for your passkey, like reading its values, and the export shows in its read log.- The update applies three database migrations to the app. They only add tables and columns.
Highlights
Workload identity
GitHub Actions jobs and Kubernetes pods read secrets without a stored token. An org admin adds a trust rule on a project's Machines tab, with their passkey: the issuer, the audience, the exact subject and claims, and the environments it grants. The job exchanges the JWT its platform issues for a token of one hour, and the CLI does that on its own when no token is set:
permissions:
id-token: write
steps:
- run: npx @kldzj/sigillo run -- ./deploy.sh
env:
SIGILLO_API_URL: ${{ vars.SIGILLO_API_URL }}
SIGILLO_PROJECT: ${{ vars.SIGILLO_PROJECT }} # the project's ID
SIGILLO_ENVIRONMENT: prodIn Kubernetes, the pod reads a projected service account token from SIGILLO_OIDC_TOKEN_FILE. External Secrets Operator works through its Doppler provider, with the controller's DOPPLER_BASE_URL set to your instance. The read log names the job or pod behind each read. See workload identity.
Warnings before tokens and trust rules expire
A token or trust rule warns in the last quarter of its lifetime, and at most its last 14 days: on the Machines tab, in a banner on the dashboard, in two response headers, and as one line on stderr from the CLI, so it shows in CI logs:
warning: this API token expires on 2026-10-13 (in 3 days). Regenerate it on the project's Machines tab; the old value then keeps working for up to 7 days.
- Regenerate a token to give it a new value and expiry. It stays the same token, with its name, scope and history, and the old value keeps working for the grace period you pick, up to 7 days but never past its own expiry. The tab shows whether anything still uses the old value, and Stop ends it early.
- Renew a trust rule to give it a new expiry. It keeps its ID, so nothing changes in your workflows or in External Secrets Operator. The renewal first shows how the rule was used, and the admin who renews it becomes the admin its tokens act for.
See before a token expires and expiry headers.
Key rotation, and purging old values
npx @kldzj/sigillo self-host --rotate-keygives your instance a new encryption key. It re-encrypts every stored value on your machine, through the D1 API, then removes the old key from the worker and ~/.sigillo/selfhost.json. Stopped halfway, the next run finishes it.
New values name their key and are bound to their environment and name, so a value copied elsewhere in the database no longer decrypts; a rotation moves the older ones over. Org admins can purge an environment's old values on its History tab, with their passkey; sigillo audit verify still finds the history intact afterwards.
Encrypted backups
npx @kldzj/sigillo self-host --backup
npx @kldzj/sigillo self-host --restore sigillo-2026-10-01T08-00-00Z.backup.ageA backup holds both databases in one file, encrypted with a backup key kept in selfhost.json, and no encryption key. A restore imports into new databases, checks every row of their history, and only then switches both workers to them. See backups.
Rewritten docs
The docs at sigillo.kldzj.dev have a quick start, pages for running an instance (updating, backups, key rotation), a security section (how Sigillo protects your secrets, protected environments, the signed history, a hardening checklist and what to do when someone leaves), and reference pages for configuration and the REST API.
Smaller changes
- The History tab lives at
…/history: the old/event-logURL matched a rule of EasyPrivacy, on by default in uBlock Origin Lite, which blocked revealing old values and purging them. self-hostchecks that a new worker's keys decrypt a stored value under every key in use before it recreates one, so a missingENCRYPTION_KEYcan't make stored secrets unreadable.- The Manage access dialog could open with Full access checked for a restricted member, so saving without changes removed the restriction.
- The device login page returns to code entry when approving fails.
- A value removed from the database without a purge now breaks the history:
sigillo audit verify, a restore and the History tab all report it. self-host --restoresays exactly what it checked, compares the history with whatsigillo audit verifysaw on your machine, needs--yeswithout a terminal, and stays unfinished until both workers use the restored databases. Backups no longer hold sign-in ID tokens.sigillo runexits128 + Nwhen its command is killed by signal N (143forSIGTERM,130for Ctrl+C), so Docker, turbo and make don't report a failure.
The key check, the access dialog, the device login page and the exit codes come from upstream Sigillo by Tommy D. Rossi, which this fork is based on.
sigillo@0.16.0
Passkeys for production: reading or changing a protected environment now takes a passkey, and so do admin actions in an organization that has one. A stolen browser session or CLI login alone can no longer read production, change it, or invite someone. The docs moved to sigillo.kldzj.dev.
Upgrading
npm i -g @kldzj/sigillo
npx @kldzj/sigillo@latest self-hostself-hostdeploys the release of its own version, and only the exact bundle that version was released with: CI records the bundle's SHA-256 in the npm package, andself-hostrefuses anything else. Use@latestto update to the newest release. It also refuses to deploy a version older than the one your instance runs, unless you pass--allow-downgrade.- Add your passkeys under user menu → Passkeys before you mark an environment Protected.
- API tokens stop reading protected environments as soon as the update is live: only machine tokens can (see below). If CI or a server reads one, sign out and in again, add a passkey, create a machine token on the Tokens tab and switch the job to it. An instance without protected environments isn't affected.
- Logins end 30 days after their sign-in, however often they're used. The CLI then asks you to run
sigillo loginagain. sigillo runskips secrets named likePATH,NODE_OPTIONS,LD_PRELOAD,GIT_PAGERornpm_config_registry, in any case, and says so. Pass--allow-env NAMEfor one you need.- Scripts that run
sigillo projects deleteorenvironments deletewithout a terminal need--yes: in a terminal, both now ask you to type the project's name or the environment's slug. - The update applies four database migrations to the app and one to the login provider. They only add tables and columns.
Highlights
Passkeys guard protected environments
Add passkeys under user menu → Passkeys: a laptop's fingerprint reader, a phone, or a security key. In an environment marked Protected:
-
In the browser, revealing, copying, downloading, saving or deleting a value asks for your passkey on the spot. One approval covers that browser for 15 minutes.
-
In the CLI, reads such as
sigillo runandsecrets get, and changes such assecrets set, print a link and a code, and wait while you approve on/approvewith your passkey:This environment is protected: approve with your passkey. Open https://secrets.acme.com/approve and enter BCDF-GHJK Waiting for your approval... ✔ Approved for 15 minutesThe code is typed, never part of the link, so a link someone sends you approves nothing.
-
Deleting or renaming a protected environment, or its project, is up to an org admin with their passkey.
The first passkey takes a Google sign-in from the last 5 minutes. Once your organization has an admin with a passkey, an admin also approves each member's first passkey on the Access tab; a member of several organizations with protected environments needs an approval from each. Leaving an organization doesn't get around its admins: they still approve the first passkey of someone who left, and an invite link made before doesn't bring them back. After that, adding or removing a passkey takes one you already have, in the same browser or with a code on /approve from another device. Admins see every passkey added or removed, and can reset a member's passkeys, which signs them out. A sole admin who lost theirs:
npx @kldzj/sigillo self-host --reset-passkeys you@acme.comAdmin actions, CLI logins and tokens
- In an organization with a protected environment, every admin action takes a passkey, covering 5 minutes: invites, roles, a member's projects, removing members, auto-join, an environment's min role or protection, resetting passkeys, machine tokens and deleting the organization.
- Once you have a passkey, approving a CLI login on
/deviceand creating an API token take it too, since both outlive the session that makes them.
Machine tokens
CI and servers can't use a passkey. An org admin creates a Machine token on the Tokens tab with their passkey: it reads and changes protected environments without one, expires after 90 days at most, and stops working when its creator is no longer an admin. Making one takes the passkey even before anything is protected, so a stolen admin session can't leave one behind for later. Other API tokens can't use protected environments. The Tokens tab also shows the IP each token was last used from.
Docs at sigillo.kldzj.dev
The docs are a static site of their own now, with a new home page. Instances serve only the app: / opens the dashboard, and every page asks search engines not to list it.
Deleting takes the name, typed out
Deleting an organization, a project, or an environment that has secrets now asks you to type its name or slug, and says what goes with it: its projects, environments and how many secrets. The server checks the typed name too. An organization's settings moved out of the project tabs into the sidebar, under Organization settings, and a project's Settings tab now renames or deletes that project.
Security
- No page of an instance or its login provider can be embedded in another site, responses are never cached, and browsers are told to use https only.
- A page or button that fails in the database says something went wrong instead of showing the query, its parameters and a stack trace.
- The API refuses a change sent with your browser's session from a page on another origin.
- An API token acts with its creator's current access: it stops when they're taken off the sign-in list, or can no longer open its project. Only a token's creator or an org admin can delete it.
- Someone removed from an organization stays removed: auto-join doesn't add them back, nor does an invite link made before. A demoted admin's invite links stop working. Anyone can leave an organization under Organization settings.
- Sign-in and login endpoints of the app and its login provider are rate limited per IP. A CLI login's device code is stored as a hash, so reading the database during a login doesn't hand out the session.
- The login provider shows its consent screen the first time an app asks, instead of skipping it for clients picked by their redirect address, and its error page links only to your instance.
- A member who can open only some projects doesn't learn the others' names, and no longer ends up in a redirect loop. Names of organizations, projects and environments can't hold control characters.
- A link to
/logouton another site asks before signing you out. - better-auth endpoints the app never uses are off, so nobody can rename themselves to appear under someone else's name.
- The history marks changes from before it existed as adopted, and
sigillo audit verifycounts them. A value starting with a byte order mark no longer breaks the history, and pages name authors as the history records them. The Hardening page says what the history can't prove. sigillo runmasks a secret that contains another one, such as a database URL with its password.sigillo loginsays which account it logged in as, no longer letsSIGILLO_API_URLreplace your saved server, keeps~/.sigillo/config.jsonreadable only by you, and opens only plain web addresses. Messages and names from the server print without terminal control characters.- The release workflow pins its GitHub Actions to commits and npm to one version, and a new push no longer cancels a release halfway.
Also
-
Git worktrees pick up the right project and env, also in subfolders: a worktree uses its main checkout's setup at the same relative path, and a setup saved inside the worktree wins. From a worktree, save it for every worktree at once:
sigillo setup --scope ~/code/repo --project website --env dev -
Each project remembers the environment you last opened.
-
The Sessions page asks a login older than a day to sign in again instead of failing.
-
Login and approval codes read
XXXX-XXXXeverywhere, with or without the dash when you type them. -
IPv6 addresses fit their columns, selects size to their content, and select lists are readable in dark mode.
-
On a phone, the menus in the navigation drawer open their links again.
-
The CLI banner on the secrets page shows
npm install -g @kldzj/sigilloand your instance's URL. -
New environment slugs are lowercase letters, digits and dashes.
sigillo@0.15.0
Hardening for self-hosted instances: signed sessions, a sign-in allowlist, a recorded and verifiable history of who read which secret, and an encrypted deploy file. The new Hardening page in your instance's docs (/docs/hardening) walks through all of it.
Upgrading
npm i -g @kldzj/sigillo
npx @kldzj/sigillo self-host- Everyone runs
sigillo loginonce. Session tokens are signed now, and CLI logins from before are refused withnot signed in, or the session expired: run sigillo login. API tokens keep working. self-hostoffers to encrypt~/.sigillo/selfhost.jsonwith a passphrase, and asks for it on every run after that. Runs without a terminal, such as CI, read it fromSIGILLO_SELFHOST_PASSPHRASE.- The update applies two database migrations to the app and one to the login provider.
Highlights
Protected environments and the Read Log
Mark an environment Protected on the Environments tab. Every read of its values is then recorded before they leave the server: who, when, which secrets, how, and from which IP. A read that can't be recorded fails. Org admins see the reads on the new Read Log tab, and turning protection off is recorded too.
The secrets page and the event log no longer load values up front. A value reaches the browser when someone reveals, downloads or copies it, so the Read Log shows who looked at which value, not who opened a page.
A history you can verify
Each environment's secret changes and reads form hash chains, signed by your instance. Editing, removing or adding a row in the database breaks the chain at that row. Org admins check it with:
sigillo audit verify -c prod✔ changes: 42 rows, intact
✔ reads: 7 rows, intact
The CLI keeps the newest row of each chain in ~/.sigillo/audit.json, so the next check also notices rows removed or rewritten since. Changes from before the upgrade join the chain on their environment's next change or check.
Limit who can sign in
npx @kldzj/sigillo self-host --allowed-users acme.com,ops@partner.ioOnly people whose verified email is on the list, or at a listed domain (not its subdomains), can sign up or sign in, in the browser and with the CLI. The app and its login provider both check it, and someone taken off the list is signed out on their next request. A refused sign-in explains why and leads back to your sign-in page.
Sessions
User menu → Sessions lists every browser and CLI login signed in as you, with its device, IP address and sign-in time. End one you don't recognize, or all but the current one. An ended session stops working on its next request. The CLI now identifies itself as sigillo-cli/<version>.
API tokens expire
New tokens last 7, 30, 90 or 365 days (90 by default), and the Tokens tab shows when each was last used. Tokens made before keep working and are marked Never, so you can replace them.
Encrypted deploy file
~/.sigillo/selfhost.json holds the keys to your deployment, so self-host now encrypts it with a passphrase (scrypt and AES-256-GCM). Keep the passphrase in your password manager and the file where it is. Change it with:
npx @kldzj/sigillo self-host --change-passphraseSecurity
- Session tokens stored in the database no longer work on their own: the CLI and API only accept the signed form, which needs your instance's secret.
- The login provider's OAuth tokens are encrypted in the database.
- Signing in with a raw
id_tokenis refused; sign-in always goes through the redirect. - better-auth and its OAuth provider plugin are on 1.7.6.
Fixes
sigillo loginstarts a new login even when a token is already saved, so a login that stopped working can be replaced.- A failed or refused sign-in no longer ends on the login provider's health check.
Published to npm through trusted publishing, with provenance.
sigillo@0.14.1
The first release of kldzj/sigillo, a maintained fork of remorses/sigillo. There is no hosted service: every instance runs on your own Cloudflare account, including its own Google login.
It contains everything on upstream's main, including security fixes upstream has not released yet (its latest release is 0.13.0), plus the fixes listed below that are only in this fork so far.
Install
npm i -g @kldzj/sigilloor the native binary:
curl -fsSL https://raw.githubusercontent.com/kldzj/sigillo/main/app/public/install.sh | bashIf you installed 0.14.0, update: it lacks the CLI token protection described under security fixes.
Highlights
Your own instance, with its own login
npx @kldzj/sigillo self-host-
Deploys two Workers with their D1 databases: the Sigillo app and its own login provider (
<name>-auth), so nothing depends on sigillo.dev or auth.sigillo.dev. -
People sign in with Google through your provider. A new deployment asks for a Google OAuth client and prints the redirect URI to register. Pass
--google-client-idand--google-client-secretfor non-interactive runs. -
New deployments get their own random
ENCRYPTION_KEY, separate from the secret that signs sessions. To choose it yourself, setSIGILLO_ENCRYPTION_KEYon the first deploy:SIGILLO_ENCRYPTION_KEY="$(openssl rand -base64 32)" npx @kldzj/sigillo self-hostBack up
~/.sigillo/selfhost.json: a database backup can't be decrypted without it. -
Re-runs update both Workers and never rotate a secret. A deployment made with upstream's
self-hostkeeps its provider, so nobody gets a new login.
No default server
The CLI never falls back to sigillo.dev. Log in to your instance once:
sigillo login --api-url https://sigillo.<your-subdomain>.workers.devAPI tokens for several environments
A token can cover dev and preview without also granting prod. Project-wide tokens still mean every environment.
Project names
--project accepts a name as well as an ID, and a wrong one is reported as a missing project instead of a missing env:
sigillo run --project website --env dev -- npm start
sigillo setup --project website --env devSecurity fixes
From upstream's main, not in an upstream release yet:
- Device login needs an explicit Approve, so a
/devicelink someone sends you can no longer sign them in as you. .envdownloads single-quote every value, sosource .envcan't run a command hidden in a secret. Secret names are validated.- The CLI never sends your saved token to a server other than the one it was saved for, and never follows a redirect with it.
run --mountwrites the file owner-only and removes it onSIGTERMandSIGHUP. - Project access and admin-only environments are enforced everywhere, not only on the secrets API, and changes apply on the next request (remorses/sigillo#12, #14).
- Deleting a project no longer unlocks every project for members limited to it, and the secrets list no longer shows names from environments you can't read.
- An API token used on an admin-only environment needs its creator to still be an org admin.
Fixes
- Deleting an API token or a user no longer deletes the secrets they wrote (remorses/sigillo#10).
- Signing in no longer fails with
Unable to parse URLwhen the login provider still has a session but hasn't been allowed for the instance yet (remorses/sigillo#16). - Changing a member's role in the access table saves again.
Only in this fork so far:
- Only one organization can claim an auto-join email domain.
- Removing a member also revokes the API tokens and invite links they created, and
sigillo logoutsigns the session out on the server. sigillo environments renameworks with only--nameor only--slug(remorses/sigillo#21).self-hostexits with status 1 when a deploy fails, so CI notices.
Published to npm through trusted publishing, with provenance.