SecretSpecがdotenv-ngをリリース、dotenvyがbcryptの認証情報を変更したと述べる

Domen Kozarのフォークにより、SecretSpecはクレデンシャル移行パスで使用されるパーサーの修正とリリースを管理できるようになった。

By · Published

Primary source: SecretSpec

Why it matters

Migration tooling cannot safely move credentials out of `.env` files if the parser changes them first. The fork gives SecretSpec control over a dependency inside its security boundary.

An exploded diagram shows the internal components of the dotenv-ng parser correctly handling an environment variable file containing a bcrypt secret and literal dollar signs.

Domen Kozar, the founder of Cachix, released dotenv-ng 1.0 after SecretSpec found that the Rust dotenvy parser it used could silently change a credential while reading a .env file.

The August 15 release grew from a narrow bug into a decision about dependency control. In Kozarの発表, SecretSpec said the new library began as a fork of dotenvy 0.15.7. SecretSpec initially considered carrying a small patch, then found enough issues around JSON, Windows paths, Unicode names, precedence and process-environment mutation to justify a breaking 1.0 rewrite.

Kozar has spent much of his career removing sharp edges from developer infrastructure. He studied telecommunications at the University of Ljubljana, participated in Google Summer of Code from 2010 through 2012, and began contributing to Nix in 2012. According to Cachix's history, he started the Nix consultancy Enlambda in 2016 and launched Cachix in 2018 to make reproducible builds and software distribution easier for engineering teams. Calm Company Fund announced an investment in Cachix in May 2020. Kozar's biography provides additional background on his work before Cachix.

The parser turned a credential into another string

The failure that triggered the fork was documented in SecretSpec issue #73, opened on April 17. A test .env file contained bcrypt fragments beginning with dollar-prefixed fields such as $2a$10. The file itself was intact, but dotenvy interpreted those fragments as variable substitutions.

The issue's reproducer shows the loaded value losing pieces of the bcrypt strings. SecretSpec encountered the damage later as an authentication failure, which sent the investigation away from the parser that caused it. The parser returned a syntactically valid value, so there was no immediate parse error pointing developers toward the actual fault.

That failure mode carries more risk than a clean rejection. A visible error stops execution near its cause. A silently modified token, password or hash can travel into an application and fail at a database, authentication service or external API, where it looks like bad credentials or a configuration mistake.

The behavior was already known upstream. A dotenvy request to disable substitution was opened on July 29, 2024, with a warning that dollar signs in environment values could disappear unexpectedly. A pull request adding the option arrived in 2026 and targeted an unreleased API. That left SecretSpec unable to rely on a published dotenvy release for configurable substitution. The repository still identifies 0.15.7, released on March 22, 2023, as its latest published release.

A fork for release control

Rust's dotenv dependency chain has already been through one maintenance handoff. The original dotenv crate stopped releasing in 2020, and RustSec classified it as unmaintained, pointing users toward dotenvy as an alternative.

Dotenvy describes itself as a well-maintained fork, yet its release gap had passed three years when the bug blocked SecretSpec. Kozar acknowledged that open-source maintainers do not owe downstream users a release. SecretSpec still needed "breaking fixes on a schedule we control".

That schedule is the strategic reason for dotenv-ng. SecretSpec handles credentials moving among local files, password managers and cloud secret stores. A parser deep in that migration path can become part of SecretSpec's security boundary even when maintained by somebody else. Forking makes Cachix responsible for the code, the compatibility breaks and the release cadence.

The tradeoff is a permanent maintenance obligation. Cachix must now track Rust changes, parser edge cases and divergent .env dialects. The dotenv-ng README says rendering follows dotenv-ng syntax and does not promise compatibility with every dotenv dialect. That narrower contract gives Kozar room to prioritize lossless parsing over inherited behavior.

What dotenv-ng changes

Dollar signs are literal by default in dotenv-ng. Applications that need variable substitution must enable it explicitly. That reverses the assumption that caused the bcrypt failure and protects passwords, hashes and tokens containing dollar-prefixed segments.

The rewrite also introduces source-aware structured errors, validates complete inputs before changing the process environment and places an explicit Rust unsafe boundary around environment mutation. Its grammar accepts dashes, leading digits, leading dots and Unicode in keys, while its renderer adds only the quoting and escaping needed for a value to survive a parse-and-render round trip.

SecretSpecによれば property tests cover arbitrary Unicode, syntax-heavy values and complete documents. Kozar also reports 100% line coverage for the parser and renderer. Those are maintainer-reported test metrics rather than evidence that every .env dialect will parse identically, a distinction the compatibility notes make clear.

Rust applications can install dotenv-ng from crates.io while retaining the familiar dotenv dependency name through a Cargo alias. The library recommends non-mutating loading for most applications and reserves environment mutation for explicit calls made before additional threads or an asynchronous runtime start.

SecretSpec wants to own the exit ramp

The fork fits an apparent contradiction in SecretSpec's product. SecretSpec argues that environment variables and .env files are poor long-term interfaces for credentials, yet it has invested in a new .env parser.

SecretSpec's homepage lists 30 providers and nine language SDK categories, spanning local keychains, password managers, Vault, cloud secret stores, SOPS, .env files and process environments. Existing .env files are often the starting point for adoption. If SecretSpec misreads those files during import or execution, its broader migration model fails before a credential reaches a safer provider.

Kozar is treating .env as an exit ramp. Owning the parser gives SecretSpec control over the first and most error-prone step: reading the user's existing credentials without changing them. Starting with SecretSpec 0.20, dotenv-ng will handle dotenv parsing and rendering throughout SecretSpec.

The release also captures a familiar founder decision in open source. A startup can wait for an upstream release, maintain a private patch or accept responsibility for a fork. Kozar chose the fork because the failure touched credential material and the upstream release schedule no longer matched SecretSpec's. The resulting library is small, but it puts a consequential dependency back under the founder's control.

Reader comments

Conversation for this story loads after sign-in.