fnox Updates & Release Notes
37 updates curated from 1 source by the Releasebot Team. Last updated: Jul 19, 2026
- Jul 17, 2026
- Date parsed from source:Jul 17, 2026
- First seen by Releasebot:Jul 19, 2026
v1.31.0: Composable Profiles
fnox adds composable multi-profile support, letting users stack multiple active profiles with ordered overrides and new profile-aware commands and builders. It also improves Proton Pass handling by pointing locked sessions to session unlock instead of a generic auth hint.
A small release headlined by composable multi-profile support, plus a friendlier Proton Pass error when your session is locked.
Added
Compose multiple active profiles (#605) -- @gaojunran
You can now activate more than one profile at a time as an ordered overlay stack. The top-level config is the base, and each profile is layered on top in order, with later profiles overriding earlier ones on key conflicts.
# Repeatable flags fnox -P aws -P prod exec -- ./app # Comma-separated fnox -P aws,prod exec -- ./app # Environment variable FNOX_PROFILE=aws,prod fnox exec -- ./appThe effective config resolves as top-level config + profiles.aws + profiles.prod, and fnox.<profile>.toml files are loaded for each active profile in order. Write commands (set, remove, import, sync, provider add/remove) target the last active profile by default, and the full profile stack is factored into the daemon's request protocol, socket path, and cache key. Library users get a new with_profiles() builder.
Fixed
Proton Pass suggests unlocking a locked session (#612) -- @TyceHerrman
pass-cli reports locked sessions as "Session is locked. Please unlock your session and try again.", but fnox previously fell through to a generic configuration/authentication hint. Locked sessions are now recognized and fnox points you at pass-cli session unlock instead of offering the configured login command. All other Proton Pass error mappings (login, key storage, agent reason, missing fields, missing secrets, generic CLI errors) are unchanged.
New Contributors
@gaojunran made their first contribution in #605
@syhol made their first contribution in #614
Full Changelog: v1.30.0...v1.31.0
π Sponsor fnox
fnox is maintained by @jdx, an open source developer for entire.io, the title sponsor of the jdx.dev open source tools including mise, aube, hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors.
If fnox is handling secrets or config for you or your team, please consider sponsoring at jdx.dev. Sponsorships are what let fnox stay independent and the project keep moving.
Original source - Jul 9, 2026
- Date parsed from source:Jul 9, 2026
- First seen by Releasebot:Jul 10, 2026
v1.30.0: Paranoid env mode and Proton Pass PAT auth
fnox releases a security-focused update with exec-only env mode, cleaner export defaults, and better Proton Pass authentication for CI and agents. It also fixes daemon cache behavior, improves secret handling in exports, and adds a redesigned logo.
A focused release that hardens fnox's secret exposure model with an exec-only env mode, expands Proton Pass authentication for CI and agent use, and cleans up fnox export defaults.
Added
Exec-only env mode and top-level env default (#604) -- @jdx
The per-secret env field gains a new "exec" state, and a new top-level env sets the default for all secrets. This lets you keep secrets out of the interactive shell -- where AI coding agents and other inherited processes would see them -- while still injecting them into fnox exec subprocesses.
env shell integration / fnox export fnox exec fnox get true (default) yes yes yes "exec" (new) no yes yes false no no yesOne line flips a project to default-deny:
env = "exec" # nothing enters the interactive shell [secrets] DATABASE_URL = { provider = "age", value = "..." } # exec-only (inherited) PS1_TOKEN = { provider = "age", value = "...", env = true } # explicit opt-in backPer-secret env overrides the top-level default, and the default rides normal config merge order so fnox.local.toml can tighten or loosen it per machine. Existing configs parse with identical semantics.
fnox doctor also warns when a shell-hiding top-level env is combined with an ambient FNOX_AGE_KEY in the environment, since that would undermine the whole posture. This eliminates ambient exposure but is not a hard boundary -- anything that can run commands in your shell can still call fnox get/fnox exec itself.
Proton Pass PAT and agent auth (#598) -- @TyceHerrman
The proton-pass provider now supports headless authentication via personal access tokens and audited agent access, so CI and scripted jobs no longer need an interactive pass-cli login --interactive.
export PROTON_PASS_PERSONAL_ACCESS_TOKEN="pst_token::key" pass-cli loginNew provider config field:
[providers.protonpass] type = "proton-pass" vault = "Personal" agent_reason = "fnox secret retrieval" # for audited agent accessfnox now passes through the full set of PROTON_PASS_* variables (PAT, agent reason, session dir, key provider, encryption key, Linux keyring) plus matching FNOX_PROTON_PASS_* aliases, and includes them in the daemon config fingerprint so cached values invalidate when auth env changes. Error messages point at the right knob when a session, key, or agent reason is missing.
Fixed
Daemon respects daemon_cache = false for default-provider secrets (#599) -- @TyceHerrman
The daemon's cache check only consulted a secret's explicit provider, so secrets that resolved through default_provider skipped the effective provider's daemon_cache setting. Cache decisions now use the effective provider in all paths (explicit provider, default_provider, and auto-selection), so opting out of daemon caching actually opts you out.
fnox export no longer leaks env = false secrets (#604) -- @jdx
fnox export previously resolved with include_env_false=true and never filtered on env, so secrets marked "only accessible via fnox get" were still included in export output -- and picked up by tools like mise-env-fnox that consume fnox export --format json. Export now follows the same shell semantics as hook-env. Pass --all for the full dump when you want it explicitly.
Changed
fnox export omits the metadata header by default (#603) -- @jdx
The env and shell export formats no longer emit the # Exported from profile: ... / # Total secrets: ... comment block by default -- output is now clean assignment lines only, easier to source or feed into other tooling. Pass --header to restore the previous behavior:
fnox export --format env --headerJSON, YAML, and TOML output are unchanged.
Redesigned logo (#595) -- @jdx
New fox-in-keyhole mark matching the fnox.jdx.dev site theme.
Full Changelog: v1.29.0...v1.30.0
π Sponsor fnox
fnox is maintained by @jdx, an open source developer for entire.io, the title sponsor of the jdx.dev open source tools including mise, aube, hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors.
If fnox is handling secrets or config for you or your team, please consider sponsoring at jdx.dev. Sponsorships are what let fnox stay independent and the project keep moving.
Original source All of your release notes in one feed
Join Releasebot and get updates from jdx and hundreds of other software products.
- Jul 1, 2026
- Date parsed from source:Jul 1, 2026
- First seen by Releasebot:Jul 3, 2026
v1.29.0: Age plugins, config-relative paths, and Nix flakes
fnox adds hardware-backed Age plugin support, more predictable config path handling, faster GCP Secret Manager batch reads, and a Nix flake. It also improves fallback defaults, expands daemon clearing across profiles, and tightens secret resolution behavior.
Added
Age plugin recipients and identities (#569) -- @nightvisi0n
The age provider now supports age plugins, so hardware-backed and specialty recipients work end to end. That includes age-plugin-yubikey (YubiKey/PIV), age-plugin-se (Apple Secure Enclave), age-plugin-tpm, and friends.
Previously a plugin recipient like age1yubikey1... failed at config load with Failed to parse recipient ... incorrect HRP because the provider only understood native X25519 and SSH recipients. It now parses age::plugin::Recipient values, spawns the matching age-plugin-* binary for encryption, and attaches UiCallbacks to identity files so AGE-PLUGIN-* identities get PIN/touch prompts on decrypt.
Nix flake (#583) -- @o-az
fnox is now packaged as a Nix flake. Consume it from another flake:
inputs.fnox.url = "github:jdx/fnox";
...then reference inputs.fnox.packages.${system}.default
Or run it directly without installing:
nix run github:jdx/fnox
The flake also exposes a devShells.default with cargo, clippy, and rustfmt.
Fixed
Defaults are used when a provider is inactive (#572) -- @jdx
If a secret declared a default and the active profile did not have the referenced provider configured, resolution would fail instead of falling back. Single-secret and batch resolution now share the same fallback path, so fnox get and fnox exec return the default (including interpolated ${...} defaults that reference other secrets resolved in the same batch) when the provider is missing, batch fetch fails, or non-interactive auth aborts. A provider value still wins when the provider succeeds; cycles between fallback defaults are rejected explicitly.
Config paths resolve relative to the config file that declares them (#582) -- @jdx
Filesystem paths in provider configuration are now interpreted against the config file that defines them, not the current working directory. This matters especially for nested/imported configs, where a parent fnox.toml could point at keys/age.key and a child config in a subdirectory would silently miss it.
Affected fields:
age.key_file
keepass.database, keepass.keyfile
password-store.store_dir
foks.home
imports, and paths reported by fnox config-files
Rules:
Paths in config files resolve relative to the declaring file, and ~ expands to the user home.
Absolute paths are used unchanged.
CLI path arguments still resolve against the current working directory.
Environment-variable paths keep their existing behavior.
fnox daemon clear clears every running daemon (#581) -- @jdx
fnox daemon clear previously only talked to the daemon socket for the current profile, so caches on daemons started under other profiles were left stale. It now scans the daemon runtime directory, sends Clear to every live profile-scoped daemon, and ignores stale sockets during the sweep. When no live daemon responds, you still get the familiar "daemon not running" error.
Changed
Faster batch reads from GCP Secret Manager (#580) -- @nils-degroot
google-secret-manager previously used the default batch implementation, which created a fresh client per secret. The provider now implements get_secrets_batch directly: a single client is reused across the batch and up to 10 secrets are fetched concurrently, which noticeably reduces latency for configs with many GCP secrets. Missing payloads and non-UTF-8 values are handled more explicitly, and client-creation errors surface provider-specific auth guidance.
New Contributors
@nightvisi0n made their first contribution in #569
@o-az made their first contribution in #583
@nils-degroot made their first contribution in #580
Full Changelog: v1.28.0...v1.29.0
π Sponsor fnox
fnox is maintained by @jdx under en.dev β a small independent studio building developer tooling like mise, aube, hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors.
If fnox is handling secrets or config for you or your team, please consider sponsoring at en.dev. Sponsorships are what let fnox stay independent and the project keep moving.
Original source - Jun 24, 2026
- Date parsed from source:Jun 24, 2026
- First seen by Releasebot:Jun 25, 2026
v1.28.0: Non-interactive exec
fnox adds a global non-interactive mode for exec and resolve flows, helping CI and scripted runs reuse cached credentials and fail fast on auth prompts or device flows. It also fixes CI Vault installs on macOS for current Homebrew tap-trust rules.
A small feature release that adds a global --non-interactive mode for fnox exec and other resolve paths, so CI and scripted runs can rely on cached credentials and fail fast instead of hanging on auth prompts or device flows.
Added
Global --non-interactive / FNOX_NON_INTERACTIVE (#565) -- @jdx
A new top-level flag (and matching env var) disables prompts and browser-based auth flows for the entire invocation. It is propagated through the daemon protocol, so daemon-backed resolution behaves the same way as direct resolution -- including when fnox auto-starts daemon serve to handle the request.
fnox --non-interactive exec -- ./run-tests.sh # or FNOX_NON_INTERACTIVE=1 fnox exec -- ./run-tests.shIn non-interactive mode:
should_prompt_auth no longer prompts, regardless of TTY or prompt_auth config.
The github-oauth lease backend still happily reuses cached and refreshable tokens, but fails immediately with a clear interactive auth required for GitHub OAuth device authorization error instead of printing a user code and polling. The error hint points you at running fnox lease create <lease-name> from an interactive terminal first.
This is intended for CI jobs, cron tasks, and other scripted runs where a hung prompt is worse than a fast failure.
Fixed
CI now installs Vault as the qualified hashicorp/tap/vault formula on macOS so Homebrew treats it as an explicitly chosen tap formula under current tap-trust rules (#567) -- @jdx
Full Changelog: v1.27.1...v1.28.0
π Sponsor fnox
fnox is maintained by @jdx under en.dev β a small independent studio building developer tooling like mise, aube, hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors.
If fnox is handling secrets or config for you or your team, please consider sponsoring at en.dev. Sponsorships are what let fnox stay independent and the project keep moving.
Original source - Jun 18, 2026
- Date parsed from source:Jun 18, 2026
- First seen by Releasebot:Jun 18, 2026
v1.27.0: Daemon, Secret Scanning, and Config Defaults
fnox adds faster secret handling with an opt-in per-user daemon, new plaintext secret scanning, and ${VAR} interpolation for secret defaults. It also includes documentation updates and CI housekeeping to round out the release.
This release adds three pieces aimed at making fnox faster, safer, and easier to compose: an opt-in per-user daemon for cached secret resolution, a new fnox scan command for finding plaintext secrets before they leak, and ${VAR} interpolation for secret defaults. It also includes a small documentation pass and CI housekeeping.
Added
Per-user secret resolver daemon (#550) -- @jdx
fnox now has an opt-in daemon that keeps resolved secrets in memory for your user session and serves repeated read-oriented resolutions over a same-user Unix socket. It is intended for configs backed by remote providers such as 1Password, Bitwarden, AWS Secrets Manager, or Vault where repeated fnox get, fnox exec, shell hooks, TUI refreshes, or MCP calls can otherwise feel slow.
Enable it with a top-level config block:
[daemon] enabled = true idle_timeout = "8h"New lifecycle commands are available under fnox daemon:
fnox daemon start fnox daemon status fnox daemon clear fnox daemon stopImplementation details worth knowing:
- Daemon-backed resolution is used by read-oriented commands such as get, exec, export, hook-env, list --values, check, tui, mcp, and ci-redact.
- Mutation and admin flows still resolve directly, including set, remove, sync, reencrypt, edit, provider, and lease create.
- The cache is memory-only and is invalidated when relevant config files, profile settings, provider references, post-processing options, or provider environment variables change.
- fnox check can connect through the daemon, but still bypasses cached values so it validates current provider state.
- Use --no-daemon, FNOX_DAEMON=off, or daemon_cache = false on a provider or secret when you need direct resolution.
- The daemon is Unix-first: it uses a Unix domain socket, strict runtime-directory permissions, and same-user peer verification rather than TCP.
fnox scan secret detection (#548) -- @jdx
fnox scan [DIR] is now implemented as a read-only repository scanner for common plaintext secrets. It walks the target tree with gitignore-aware traversal, skips common VCS/build/vendor directories and large or binary files, and reports high-signal patterns with redacted evidence.
Supported output modes include human-readable output, JSON, and quiet file-list output:
fnox scan fnox scan --format json fnox scan --quiet src fnox scan --ignore 'fixtures/**'The scanner reports line and column, detector name, severity, and a redacted snippet. Findings return a scan-specific non-zero error so the command can be used in automation.
Secret default interpolation (#549) -- @jdx
Secret default strings can now reference other secrets with ${SECRET_NAME} syntax. This makes fallback-only configs easier to compose without duplicating literals, for example when building a local connection URL from sibling defaults.
Provider-backed values still win over defaults, and interpolation only runs when the default value is actually used. Batch resolution now includes default references in dependency ordering, so composed defaults are resolved order-independently. fnox also reports config errors for undefined references, empty ${} placeholders, and interpolation cycles.
Documentation
Sponsor links (#543) -- @jdx
Documentation now links to the full sponsor list.
Contribution guidance (#545) -- @jdx
The contribution docs now clarify what kinds of changes are a good fit for the project.
Other Changes
Shared CodeRabbit config (#546) -- @jdx
CI now uses the shared repository review configuration.
Full Changelog: v1.26.0...v1.27.0
π Sponsor fnox
fnox is maintained by @jdx under en.dev β a small independent studio building developer tooling like mise, aube, hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors.
If fnox is handling secrets or config for you or your team, please consider sponsoring at en.dev. Sponsorships are what let fnox stay independent and the project keep moving.
Original source Similar to fnox with recent updates:
- Claude Code updates403 release notes Β· Latest Jul 22, 2026
- Claude updates116 release notes Β· Latest Jul 14, 2026
- Firefox updates36 release notes Β· Latest Jul 21, 2026
- Safari updates22 release notes Β· Latest Jun 8, 2026
- iOS updates26 release notes Β· Latest Jun 9, 2026
- macOS updates26 release notes Β· Latest Jun 9, 2026
- Jun 18, 2026
- Date parsed from source:Jun 18, 2026
- First seen by Releasebot:Jun 18, 2026
v1.27.1: dotenv exports and a Windows build fix
fnox ships a small patch release that fixes dotenv exports, adds a separate sourceable shell format, and unbreaks Windows builds. It also updates import round-tripping for quoted secrets and notes a breaking change for export --format env output.
A small patch release that makes fnox export actually produce dotenv files, adds a separate shell format for sourceable output, and unbreaks the Windows build introduced by the v1.27.0 daemon.
Fixed
fnox export --format env now emits real dotenv (#554) -- @jdx
The env format was documented as .env/KEY=value but was actually emitting shell export KEY='value' lines, which broke consumers that expect bare assignments. It now produces proper dotenv output:
$ fnox export --format env NORMAL_SECRET=normal-value SPECIAL_SECRET="secret$value`tick`" QUOTED_SECRET="quoted \"value\" with \\ backslash"Simple values are left unquoted; values containing whitespace or special characters are double-quoted with \n, \r, \t, ", and \ escaped. $ and backticks are deliberately left literal so the file round-trips through dotenv parsers.
fnox import was updated to match: double-quoted .env values now have \n, \t, ", and \ unescaped on the way in, so an export/import round-trip preserves multi-line and quoted secrets.
Windows builds fixed (#555) -- @jdx
The v1.27.0 daemon imported std::os::fd::AsRawFd and tokio::net::Unix{Listener,Stream} at module scope, which broke cargo check on Windows even though the daemon runtime is Unix-only. Those imports and the connection handler are now gated behind #[cfg(unix)], and a cargo check job on windows-latest was added to CI so this can't regress silently.
Added
fnox export --format shell (#554) -- @jdx
A new shell format emits sourceable POSIX export KEY=value statements with proper shell quoting -- this is the behavior the old env format had, now under its correct name:
fnox export --format shell > secrets.sh source secrets.shDocumentation
Added Doppler to the cloud secret manager list in the README (#552) -- @bowenc
Breaking Changes
fnox export --format env output changed from export KEY='value' to KEY=value. If you were sourcing that output in a shell, switch to fnox export --format shell to get the old behavior.
New Contributors
@bowenc made their first contribution in #552
Full Changelog: v1.27.0...v1.27.1
π Sponsor fnox
fnox is maintained by @jdx under en.dev β a small independent studio building developer tooling like mise, aube, hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors.
If fnox is handling secrets or config for you or your team, please consider sponsoring at en.dev. Sponsorships are what let fnox stay independent and the project keep moving.
Original source - Jun 17, 2026
- Date parsed from source:Jun 17, 2026
- First seen by Releasebot:Jun 17, 2026
- Jun 12, 2026
- Date parsed from source:Jun 12, 2026
- First seen by Releasebot:Jun 16, 2026
v1.26.0: Provider-Backed Age Identities & Vault Credential Commands
fnox adds more flexible authentication, letting age identities bootstrap from another provider and Vault tokens come from a user-defined shell command. It also brings real GCP Secret Manager writes plus fixes for fnox export and hook-env in shell pipelines.
A feature release centered on more flexible authentication: the age provider can now bootstrap its identity from another provider (for example, the OS keychain), and the Vault provider and lease backend can obtain tokens from a user-defined shell command. Also includes a real put_secret_value for GCP Secret Manager and two fixes that make fnox export and hook-env better citizens in shell pipelines.
Added
Provider-backed age identities (#515) -- @k35o
The age provider now accepts an identity reference that resolves through any other configured provider. This makes the keychain-bootstrap pattern from v1.25.1 actually work end-to-end:
[providers] keychain = { type = "keychain", service = "fnox" } age = { type = "age", recipients = ["age1..."], identity = { provider = "keychain", value = "age-key" } }Implementation details worth knowing:
Identities are resolved lazily during decryption, so fnox set and other encryption-only paths don't require access to the backing identity provider.
Resolution order is FNOX_AGE_KEY -> identity provider ref -> key_file -> deprecated CLI setting -> default ~/.config/fnox/age.txt.
Cycle detection catches both direct self-references (age -> age) and mutual cycles between two age providers, producing a clear Circular dependency detected in provider configuration: age-a -> age-b -> age-a error.
Nested age identities are supported: a bootstrap age provider can decrypt the identity used by a second age provider.
Identity providers that require interactive auth are rejected in non-interactive mode with a hint to use fnox exec.
credential_command for Vault provider and lease backend (#526) -- @jdx
Vault and OpenBao users can now resolve tokens through a configured shell command when no static token is provided, removing the need to share or pre-stage a VAULT_TOKEN:
[providers.vault_team_a] type = "vault" address = "$VAULT_ADDR" namespace = "team-a" path = "secret/team-a" credential_command = "vault login -method=oidc -token-only"The same field is available on the Vault lease backend:
[leases.vault-db] type = "vault" address = "$VAULT_ADDR" credential_command = "vault login -method=oidc -token-only" secret_path = "database/creds/readonly" method = "post"Commands run through the platform shell (sh -c / cmd /C), so pipes and redirects work.
The string is rendered as a Tera template with address, path/secret_path, and namespace available as variables, and fnox injects VAULT_ADDR and VAULT_NAMESPACE into the environment.
Output is cached for ~5 minutes per process so resolving many secrets from the same provider doesn't repeat the login.
401/403 responses from Vault invalidate the cache so a stale token is refetched on the next call.
Static config/env tokens still take precedence; credential_command is only consulted when no token is configured.
FNOX_VAULT_NAMESPACE is now recognized alongside VAULT_NAMESPACE.
put_secret_value for GCP Secret Manager (#530) -- @nils-degroot
The GCP Secret Manager provider's write path was previously a stub that returned put_secret not yet implemented. fnox set --provider gcp now actually writes: it adds a new secret version, and on 404 NOT_FOUND it creates the secret with automatic replication and retries the write. PERMISSION_DENIED responses surface as ProviderAuthFailed with the relevant IAM permission name (secretmanager.versions.add / secretmanager.secrets.create).
Fixed
FIDO2 keep-alive messages no longer corrupt fnox export (#506, resolves #465) -- @baprx
ctap-hid-fido2's "touch your key" prompts were being written to stdout, which broke eval "$(fnox export)" and similar shell-sourcing workflows. fnox now configures the FIDO2 client with with_keep_alive_msg_to_stderr(true) for both secret retrieval and setup, so stdout stays clean for the exported assignments.
hook-env respects $COLUMNS when stderr is not a TTY (#523) -- @davidolrik
Shell hooks capture stderr, so console::Term::size() could return a useless width when rendering the env-change summary. fnox now uses the TTY width when available, then $COLUMNS, and falls back to 80 columns β restoring the previous default and producing readable truncation in shell hooks.
Documentation
AWS Secrets Manager IAM requirements (#513) -- @gaffneyc
The docs now make clear that BatchGetSecretValue (introduced for batched lookups) must be granted alongside ListSecrets with a wildcard resource β neither action accepts a resource ARN scope.
New Contributors
@nils-degroot made their first contribution in #530
@k35o made their first contribution in #515
@gaffneyc made their first contribution in #513
@baprx made their first contribution in #506
Full Changelog: v1.25.1...v1.26.0
π Sponsor fnox
fnox is maintained by @jdx under en.dev β a small independent studio building developer tooling like mise, aube, hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors.
If fnox is handling secrets or config for you or your team, please consider sponsoring at en.dev. Sponsorships are what let fnox stay independent and the project keep moving.
Original source - May 17, 2026
- Date parsed from source:May 17, 2026
- First seen by Releasebot:May 17, 2026
v1.25.1: Keychain reliability and dependency refreshes
fnox ships a patch release that fixes macOS keychain deadlocks and dialog storms, updates the keyring stack to keyring-core v1, and adds KeePass 0.12 support. It also improves secret error handling and recommends using the keychain for bootstrap secrets only.
A patch release focused on the OS keychain provider: a deadlock and dialog-storm fix on macOS, plus a clean migration to keyring-core v1 and keepass 0.12.
Fixed
Keychain provider no longer deadlocks the runtime or stacks dialogs (#495) -- @jdx
Resolving several keychain-backed secrets at once on macOS could hang fnox indefinitely (see discussion #489). The default batch path fans out 10 concurrent reads, which surfaced up to 10 overlapping "Always Allow / Allow / Deny" Security dialogs and pinned every tokio worker thread waiting for the user β deadlocking the runtime.
Two changes fix this:
All keyring-core calls (set_password, get_password, delete_credential) now run via tokio::task::spawn_blocking, so a blocked Security dialog never pins a runtime worker.
The keychain provider overrides get_secrets_batch to resolve entries serially, so dialogs appear one at a time and Ctrl-C stays responsive.
fnox set against the keychain and test_connection are routed through the blocking pool too.
KeePass provider works with keepass 0.12 (#494) -- @jdx
The 0.10 β 0.12 bump made Group.groups, Group.entries, Database.root, and friends pub(crate), with access now going through Database::root(), GroupRef/GroupMut accessors, and add_group / add_entry. The provider has been rewritten to match:
Entry lookup returns an EntryId and resolves to EntryRef / EntryMut via Database::entry / entry_mut, avoiding lifetime issues with recursive GroupRef borrows.
Writes navigate and create groups segment-by-segment via group_mut / add_group, then update or add_entry.
Field writes use the new set_protected / set_unprotected helpers, preserving "Password protected, everything else unprotected" behavior.
Lookup semantics are unchanged: path segments before the last name exact-named subgroups; the final segment is searched recursively by entry title.
Changed
Migrate from keyring v3 to keyring-core v1 (#493) -- @jdx
Upstream keyring v4 is now just a CLI/sample app β the library moved to keyring-core plus per-platform credential-store crates. fnox now depends on:
apple-native-keyring-store (with the keychain feature) on macOS
windows-native-keyring-store on Windows
dbus-secret-service-keyring-store (with crypto-rust + vendored) on Linux
A new fnox_core::keyring_store::init() lazily registers the default store once per process; both the keychain provider and the github_oauth lease backend invoke it before constructing an Entry. Error classification now matches keyring_core::Error::{NoEntry, NoStorageAccess(_)} enum variants instead of string-matching error messages, producing more accurate ProviderSecretNotFound vs ProviderAuthFailed errors.
No config or CLI surface changes β the keychain provider and github_oauth lease backend keep the same TOML fields and behavior.
Documentation
Use the keychain for a bootstrap key, not bulk storage (#495) -- @jdx
The keychain provider docs now recommend storing a single age identity in the OS keychain and encrypting the rest of your secrets with the age provider, so you hit one "Always Allow" prompt instead of one per secret:
[providers] keychain = { type = "keychain", service = "fnox" } age = { type = "age", recipients = ["age1..."], identity = { provider = "keychain", value = "age-key" } } [secrets] DATABASE_URL = { provider = "age", value = "encrypted..." } API_KEY = { provider = "age", value = "encrypted..." } STRIPE_KEY = { provider = "age", value = "encrypted..." }Reach for provider = "keychain" directly only for the handful of bootstrap secrets that have nothing else to decrypt them.
Full Changelog: v1.25.0...v1.25.1
π Sponsor fnox
fnox is maintained by @jdx under en.dev β a small independent studio building developer tooling like mise, aube, hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors.
If fnox is handling secrets or config for you or your team, please consider sponsoring at en.dev. Sponsorships are what let fnox stay independent and the project keep moving.
Original source - May 14, 2026
- Date parsed from source:May 14, 2026
- First seen by Releasebot:May 15, 2026
v1.25.0: FOKS provider and clean pipe handling
fnox adds a new FOKS provider for the Federated Open Key Service, bringing end-to-end encrypted secret storage with personal and team-scoped configs, CI-friendly bot auth, and a cleaner config scaffold. It also fixes broken-pipe panics and updates the docs version label.
Adds a new foks provider for the FOKS end-to-end encrypted KV store, and fixes a long-standing panic when piping fnox get into a process that closes the pipe early.
Added
foks provider for the Federated Open Key Service (#486) -- @maxtaco
A new provider that stores secrets in a FOKS end-to-end encrypted KV store via the foks CLI. Supports both personal and team-scoped configurations:
[providers] foks = { type = "foks", prefix = "fnox/" } # personal ops = { type = "foks", prefix = "fnox/", team = "ops" } # team-shared [secrets] DATABASE_URL = { provider = "ops", value = "DATABASE_URL" }Configurable fields:
prefix β path namespace within the FOKS KV store
team β FOKS team to scope to (passed through as --team)
home β custom FOKS home dir (passed as --home); falls back to FNOX_FOKS_HOME / FOKS_HOME
host, bot_token β non-interactive auth for CIWhen bot_token and host are configured (or FOKS_BOT_TOKEN / FOKS_HOST are set in env), the provider transparently runs foks bot use --host on the first auth failure and retries the operation, so CI just needs:
env: FOKS_BOT_TOKEN: ${{ secrets.FOKS_BOT_TOKEN }} steps: - run: brew install foks - run: foks ctl start - run: fnox exec -- ./deploy.shThe auto-login fires at most once per provider instance (mutex-guarded), so concurrent secret fetches don't dogpile and bad tokens surface as a clear ProviderAuthFailed. Scaffold a config block with fnox provider add foks foks. See the FOKS provider docs for the full reference.
Fixed
Exit cleanly on SIGPIPE instead of panicking (#487) -- @maxtaco
fnox get FOO | previously panicked because Rust inherits SIG_IGN for SIGPIPE from libc, so writes to a closed pipe returned EPIPE and println! blew up:
Error: Γ Main thread panicked.
β°ββΆ failed printing to stdout: Broken pipe (os error 32)fnox now resets SIGPIPE to SIG_DFL at startup and dies from the signal like a normal Unix tool. Pipelines such as fnox get TRAILING | cat -A (where BSD cat rejects -A and exits) now produce a clean 141 exit code instead of a Rust panic.
Docs site version label (#483) -- @jdx
After the workspace migration, the VitePress config's regex still looked for version = "..." under [package], but the literal version now lives under [workspace.package]. The docs nav was falling back to v0.0.0; it now reads the real version.
New Contributors
@maxtaco made their first contribution in #486
Full Changelog: v1.24.1...v1.25.0
π Sponsor fnox
fnox is maintained by @jdx under en.dev β a small independent studio building developer tooling like mise, aube, hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors.
If fnox is handling secrets or config for you or your team, please consider sponsoring at en.dev. Sponsorships are what let fnox stay independent and the project keep moving.
Original source - May 13, 2026
- Date parsed from source:May 13, 2026
- First seen by Releasebot:May 13, 2026
v1.24.1: Safer shell activation and table-style secret edits
fnox ships a small bug-fix release that strengthens secret handling, preserves multi-line secret table formatting during edits, and prevents bash and zsh activation from expanding secret values. It also updates the Mise integration guidance.
A small bug-fix release that hardens shell activation against expansion of secret values and stops fnox set / fnox import from rewriting [secrets.NAME] tables as inline tables.
Fixed
Preserve table-style secret formatting on edits (#467) -- @jdx
fnox set and fnox import previously rewrote any existing
[secrets."NAME"]table as a single-line inline table ("NAME" = { provider = ..., value = ... }), discarding the multi-line layout. Both commands now detect the existing style and update fields in-place, keeping the[secrets."NAME"]header, comments, and key order intact:[secrets."SEKRIT_PASSWORD"] provider = "age" value = "..." # updated in place if_missing = "error" # preservedPrevent shell expansion of secret values in bash/zsh activation (#473) -- @jdx
The bash and zsh hook-env output previously wrapped values in double quotes with only
\and"escaped, so a secret containing$$,`cmd`, or${...}would be expanded by the shell when the activation script was eval-ed β leaking e.g. the shell PID into the variable (see discussion #471). fnox now POSIX-quotes values via shlex, producing safe single-quoted output:export DOLLAR_SECRET='$$test' export BACKTICK_SECRET='a`whoami`b'Values now round-trip through eval unchanged. Fish, PowerShell, and Nushell were already unaffected.
Documentation
Mise integration guide now recommends installing fnox with mise and using shell integration or fnox exec; the jdx/mise-env-fnox env plugin is flagged as experimental and incomplete (#472) -- @jdx
Full Changelog: v1.24.0...v1.24.1
π Sponsor fnox
fnox is maintained by @jdx under en.dev β a small independent studio building developer tooling like mise, aube, hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors.
If fnox is handling secrets or config for you or for your team, please consider sponsoring at en.dev. Sponsorships are what let fnox stay independent and the project keep moving.
Original source - May 6, 2026
- Date parsed from source:May 6, 2026
- First seen by Releasebot:May 7, 2026
v1.24.0: GitHub OAuth lease backend
fnox adds a new github-oauth lease backend for short-lived, user-attributed GitHub tokens via the OAuth device flow, without requiring an app private key. It supports cached token reuse, transparent refreshes, configurable env vars, and GitHub Enterprise Server settings.
A focused release that adds a new github-oauth lease backend for minting short-lived, user-attributed GitHub tokens via OAuth device flow β without distributing an app private key.
Added
- github-oauth lease backend (#464) -- @jdx
A new lease type that creates GitHub App user access tokens using the OAuth device flow and injects them as GITHUB_TOKEN (or a custom env var) for the duration of fnox exec. It is the recommended option for local development and user-attributed gh / GitHub API usage where you want a short-lived token tied to the signed-in user instead of a long-lived PAT in fnox.toml.
[leases.github] type = "github-oauth" client_id = "Iv1.yourgithubappclientid" scope = "repo read:org workflow" duration = "8h"fnox exec -- gh pr listOn first run, fnox prints a verification URL and user code, optionally opens the URL in your browser, and polls GitHub until you approve the device prompt. Subsequent runs reuse the cached token until it expires.
Highlights of the backend:
- Only the GitHub App client ID is required β no app private key and no client secret, so the lease config can be checked in and shared across a team. (The existing github-app backend remains the right choice for installation tokens in CI.)
- OS keyring caching of access and refresh tokens, keyed by client id + scope + endpoints. Disable with keyring_cache = false to force the device flow on every lease.
- Refresh token reuse when GitHub issues one β refreshes happen transparently; if the refresh fails, fnox falls back to a fresh device flow.
- Configurable env var via env_var (e.g. "GH_TOKEN") and configurable auth_base / api_base for GitHub Enterprise Server.
- open_browser controls whether fnox tries to launch the verification URL automatically (uses open / xdg-open / start).
The supported-backends table in the leases guide is updated, and the github-app docs now point local/user-attributed workflows at github-oauth. See the GitHub OAuth lease docs for the full reference.
Full Changelog: v1.23.1...v1.24.0
π Sponsor fnox
fnox is maintained by @jdx under en.dev β a small independent studio building developer tooling like mise, aube, hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors.
If fnox is handling secrets or config for you or your team, please consider sponsoring at en.dev. Sponsorships are what let fnox stay independent and the project keep moving.
Original source - May 2, 2026
- Date parsed from source:May 2, 2026
- First seen by Releasebot:May 2, 2026
v1.23.1: Alpine binaries and fnox-core crate
fnox adds native musl Linux binaries for Alpine users and splits its library into a new fnox-core crate for downstream Rust consumers, while also updating the docs site with refreshed icons and web manifest support.
A small release that ships native musl binaries for Alpine users and splits the library half of fnox into its own fnox-core crate for downstream Rust consumers.
Added
musl Linux binaries (#452) -- @jdx
Releases now include x86_64-unknown-linux-musl and aarch64-unknown-linux-musl artifacts alongside the existing gnu builds. The previous glibc-linked binaries failed on Alpine with cannot execute: required file not found (missing libudev.so.1 and glibc-only symbols like __res_init) β even with gcompat installed. The musl builds are statically linked and run cleanly on alpine:3 and friends:
docker run --rm -v "$PWD:/work" alpine:3 sh -c \ 'cd /work && tar xzf fnox-*-x86_64-unknown-linux-musl.tar.gz && ./fnox --version'Note: the fido2 provider is not compiled into musl builds (its ctap-hid-fido2 dependency doesn't build under musl). Alpine users needing hardware-key-style flows should use age, pass, or a cloud provider. The keychain provider compiles but, as on any headless Linux, requires a session bus at runtime.
Docs site favicons and web manifest (#448) -- @jdx
Adds a simplified vault-door favicon.svg plus favicon.ico, 16/32 PNGs, apple-touch-icon.png, Android Chrome icons, and a site.webmanifest for installable-PWA metadata.
Changed
fnox-core library crate (#458) -- @jdx
The repo is now a Cargo workspace, and the library half of fnox β every provider, the Provider trait, Config, SecretResolver, lease backends, settings, and the top-level Fnox API introduced in v1.22 β lives in a new fnox-core crate under crates/fnox-core/. The root fnox crate keeps the CLI-only pieces (commands, MCP server, TUI, shell integration, hook-env).
This is a pure refactor with no behavior change. Existing Rust consumers don't need to update imports: the binary crate's lib.rs re-exports every fnox-core module, so fnox::providers::, fnox::config::, fnox::Fnox, etc. continue to resolve. Projects that want a leaner dep tree can now depend on fnox-core directly instead.
Docs nav star badge (#447) -- @jdx
The GitHub link in the docs top-nav now reads β N instead of a bare number, and the count is actually populated on the live site β the deploy workflow now passes GITHUB_TOKEN to the VitePress build so stars.data.ts can hit the GitHub API at build time.
Full Changelog: v1.23.0...v1.23.1
π Sponsor fnox
fnox is maintained by @jdx under en.dev β a small independent studio building developer tooling like mise, aube, hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors.
If fnox is handling secrets or config for you or your team, please consider sponsoring at en.dev. Sponsorships are what let fnox stay independent and the project keep moving.
Original source - Apr 26, 2026
- Date parsed from source:Apr 26, 2026
- First seen by Releasebot:Apr 27, 2026
v1.23.0: Line selector for multiline secrets
fnox adds a line selector for multiline secrets, letting users expose a single line from a pass entry as its own secret. It supports 1-indexed line picking, clear error handling, and read-only projection for cached secrets and reencrypt flows.
A small, focused release that adds a line selector for picking a single line out of a multiline secret β most useful for the pass convention of storing the password on line 1 and metadata (username, URL, etc.) on subsequent lines.
Added
Line selector for multiline secrets (#446) -- @fgrosse
Secrets now accept a 1-indexed line field that returns just the Nth line of the resolved value. This matches the pass show <entry> --clip=N convention and lets you expose multiple fields from a single pass entry as separate secrets:
[providers.pass] type = "password-store" prefix = "fnox/" [secrets] # `pass show fnox/database` returns: # <password> # <username> DB_PASSWORD = { provider = "pass", value = "database", line = 1 } DB_USERNAME = { provider = "pass", value = "database", line = 2 }Details worth knowing:
- line is mutually exclusive with json_path; using both on the same secret is an error.
- Line splitting uses str::lines(), so \r\n endings are handled cleanly and a single trailing newline doesn't shift indices.
- line = 0 and out-of-range values produce clear error messages (e.g.
line = 5is out of range; secret has 2 line(s)). - Post-processing applies uniformly to provider, default, and env-var sources.
- fnox sync and fnox reencrypt cache the raw provider value, not the post-processed view, so the selector stays a read-only projection.
- fnox set still overwrites the entire entry β line is read-only. Edit individual lines of an existing entry with pass edit <entry>.
- See the password-store provider docs for a full walkthrough.
New Contributors
@fgrosse made their first contribution in #446
Full Changelog: v1.22.0...v1.23.0
π Sponsor fnox
fnox is maintained by @jdx under en.dev β a small independent studio building developer tooling like mise, aube, hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors.
If fnox is handling secrets or config for you or your team, please consider sponsoring at en.dev. Sponsorships are what let fnox stay independent and the project keep moving.
Original source - Apr 26, 2026
- Date parsed from source:Apr 26, 2026
- First seen by Releasebot:Apr 27, 2026
v1.22.0: Library API and a sticky-provider fix for `fnox set`
fnox releases v1.22.0 with a new top-level Rust library API for embedding, safer secret updates that keep encrypted values encrypted, and more deterministic schema generation. It also improves docs and adds a dismissible announcement banner.
Added
Top-level Fnox library API (#442) -- @bglusman
Downstream Rust consumers can now use fnox as a library in three lines instead of replicating the internals of GetCommand::run:
use fnox::Fnox; let fnox = Fnox::discover()?; // walks up + merges parent + local + global config let value = fnox.get("MY_KEY").await?; let names = fnox.list()?;The new Fnox type lives in src/library.rs and is re-exported from the crate root. Highlights:
Fnox::discover() mirrors the binary's full config-discovery and merge chain via Config::load_smart, including the FNOX_PROFILE env var.
Fnox::open(path) loads an explicit config without the upward-search/merge behavior.
Fnox::with_profile("staging") builder for non-default profiles.
get() returns FnoxError::SecretNotFound with a populated "Did you meanβ¦" suggestion, matching the CLI's UX so callers don't need to recompute it.
Fnox is cheap to clone (Config is held behind an Arc) and safe to hold across .await.
set() is intentionally not part of this first cut; it'll get its own design pass.
Fixed
fnox set no longer silently downgrades encrypted secrets to plaintext (#439) -- @rpendleton
When multiple providers were configured without a default_provider, running fnox set on an existing secret without --provider would write the new value as plaintext while leaving the original provider = "..." key in place. The next fnox get then failed trying to "decrypt" a value that was no longer encrypted.
fnox set now reuses the secret's existing provider before falling back to default_provider or plaintext, so updates stay encrypted and readable without having to pass --provider on every call:
fnox set --provider age MY_SECRET "original-value" # encrypted with age fnox set MY_SECRET "new-value" # still encrypted with ageDeterministic provider ordering in the generated schema (#432) -- @jdx
Within-category provider ordering in build/generate_providers.rs was inheriting fs::read_dir order, which is OS- and filesystem-dependent. That non-determinism flowed into docs/public/schema.json and caused autofix.ci to keep reshuffling 100+ lines between runs. A secondary sort by provider name fixes the churn; running fnox schema twice now produces byte-identical output.
Mobile docs banner layout (#437) -- @jdx
At <=640px the announcement banner now switches to a column layout with the close button pinned to the top-right corner, instead of cramming the message and "Read more" link onto one squeezed line.
Changed
Docs site nav now shows the current release version (read from Cargo.toml at build time) and a GitHub star count, matching the mise/aube docs (#443) -- @jdx
Added a dismissible cross-site announcement banner that fetches its config from jdx.dev/banner.json and respects the expires field (#434, #436) -- @jdx
New Contributors
@bglusman made their first contribution in #442
Full Changelog: v1.21.0...v1.22.0
π Sponsor fnox
fnox is maintained by @jdx under en.dev β a small independent studio building developer tooling like mise, aube, hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors.
If fnox is handling secrets or config for you or your team, please consider sponsoring at en.dev. Sponsorships are what let fnox stay independent and the project keep moving.
Original source
Curated by the Releasebot team
Releasebot is an aggregator of official product update announcements from hundreds of software vendors and thousands of sources.
Our editorial process involves the manual review and audit of release notes procured with the help of automated systems.