Stop committing .env files. Stop hoping a leak doesn't happen.
A cross-stack, zero-trust secret management library for Node.js and Java/Spring Boot β with optional TOTP-based unsealing for production deploys.
Docs Β· Threat Model Β· File Format Β· Security Policy Β· Landing
In 2025 alone, supply-chain attacks on the JavaScript ecosystem stole thousands of
plaintext secrets from CI/CD pipelines and developer machines. The Shai-Hulud worm
(November 2025) compromised over 25,000 repositories by scanning for .env files
and exfiltrating their contents to public GitHub repos. On May 12, 2026, TeamPCP
open-sourced the full framework on GitHub; clones appeared within 48 hours.
The lesson is simple: plaintext .env is dead. And encrypted-at-rest alone isn't
enough β if the master key leaks (and they do β see the tj-actions and GhostAction
campaigns), the entire vault opens.
sealed-env solves both halves: it encrypts your secrets at rest, and it can require
a fresh TOTP code from a human operator before each production deploy. Even if your CI
pipeline is fully compromised, attackers cannot decrypt without the operator's phone.
Honest scope claim: sealed-env reduces the impact of Shai-Hulud-class supply-chain attacks by keeping master keys out of disk and
process.envwhen configured withsealed-env keychain pushand enterprise mode + short-TTL unseal tokens. It does not prevent the initial compromise of a developer machine or CI runner. Full per-module analysis:threat-research/analysis/shai-hulud-defense.md. Runsealed-env doctorfor an automated posture check.
- A
.env.sealedfile format that's identical across Node and Java. Mix stacks freely. - Three security modes the user picks:
basicfor dev,teamfor staging,enterprisefor production with TOTP unseal. - Zero runtime dependencies in the Node package. Only Node's built-in
cryptoandfs. - A published threat model that says exactly what we defend against and what we don't.
- A CLI (
npx sealed-env) and a Spring Boot starter (Java).
βββββββββββββββββββββββββββ βββββββββββββββββββββββββββ
β Node side β β Java side β
β ββββββββββββ β β ββββββββββββ β
β β’ CLI: sealed-env seal β β β’ SealedEnv core lib β
β β’ npm: sealed-env β β β’ Spring Boot starter β
β β’ writes KDF=scrypt β β β’ writes KDF=argon2id β
ββββββββββββββ¬βββββββββββββ ββββββββββββββ¬βββββββββββββ
β β
β both speak SEALED-ENV-V1 β
β (byte-for-byte spec compliance) β
βΌ βΌ
ββββββββββββββββββββββββββββββββββββββββββ
β .env.sealed β
β βββββββββββββββββββββββββββ β
β SEALED-ENV-V1 MODE=team β
β KDF=<scrypt|argon2id> β
β KDF-PARAMS=... SALT=... β
β NONCE=... AAD-DIGEST=... β
β HMAC=... CREATED=2026-... β
β β
β <base64 ciphertext + GCM tag> β
ββββββββββββββββββββββββββββββββββββββββββ
β² β²
β a file written by one β
β stack decrypts in the β
β other β no conversion β
β β
ββββββββββββββ΄βββββββββββββ ββββββββββββββ΄βββββββββββββ
β Node app reads it β β Java app reads it β
β (loadSealed()) β β (Spring Environment) β
βββββββββββββββββββββββββββ βββββββββββββββββββββββββββ
From 0.2.1 onwards, every npm release ships with SLSA Build Level 3
provenance signed via Sigstore through GitHub Actions trusted
publishing. After installing, you can confirm that the tarball was
built from the source we publish (not from a compromised pipeline):
npm audit signatures sealed-envExpect output that includes verified for sealed-env with a
signature link to a Sigstore transparency log entry. If the command
reports anything else, do not run sealed-env β open an issue first.
This is a real check, not a marketing pixel: the TanStack supply-chain
attack of May 2026 published malicious packages with valid-looking
SLSA Build Level 3 provenance, so provenance alone is insufficient.
But combined with version pinning + release-age cooldowns (pnpm 11 minimumReleaseAge: 24h or yarn npmMinimalAgeGate: 3d), it's a
meaningful defensive layer.
# 1. Install
npm install sealed-env
# 2. Initialize a vault for your project
npx sealed-env init
# β generates a master key (saved locally to .env.local, gitignored)
# β if you choose 'enterprise' mode, also displays a QR code for your authenticator
# 3. Encrypt your existing .env
npx sealed-env encrypt .env
# β creates .env.sealed (commit this!)
# 4. Use it in code β no API change
import 'sealed-env/config';
console.log(process.env.STRIPE_API_KEY); // works as if it were a normal .env<dependency>
<groupId>io.github.davidalmeidac</groupId>
<artifactId>sealed-env-spring-boot-starter</artifactId>
<version>0.1.0</version>
</dependency># application.yml
sealed-env:
file: .env.sealed
key-source: env@Value("${stripe.api.key}") // resolved transparently from .env.sealed
private String stripeKey; basic team enterprise
βββββ ββββ ββββββββββ
.env.sealed .env.sealed .env.sealed
β β β
βΌ βΌ βΌ
βββββββββββ βββββββββββ βββββββββββ
β AES-GCM β β HMAC β β HMAC β
β decrypt β β verify β β verify β
ββββββ¬βββββ ββββββ¬βββββ ββββββ¬βββββ
β βΌ βΌ
βΌ βββββββββββ βββββββββββ
plaintext β AES-GCM β β TOTP β
β decrypt β β token β
ββββββ¬βββββ β verify β
βΌ ββββββ¬βββββ
plaintext βΌ
βββββββββββ
β² β² β deploy β
β master_key β + signing_key β bind β
ββββββ¬βββββ
βΌ
βββββββββββ
β AES-GCM β
β decrypt β
ββββββ¬βββββ
βΌ
plaintext
β²
β + unseal token (carries
β salt-bound TOTP epoch)
β + deploy_id
| basic | team | enterprise | |
|---|---|---|---|
| AES-256-GCM cipher | β | β | β |
| Argon2id key derivation | β | β | β |
| HMAC integrity tag | β | β | β |
| TOTP unseal required | β | β | β |
| Deploy-bound unseal tokens | β | β | β |
| Replay protection | β | β | β |
| Memory wipe after read | β | β | β |
Host-side decrypt (deploy --remote) |
β | β | β |
| Suitable for | personal projects | staging, small teams | production, fintech, PII |
Pick the one that fits your threat model. Upgrade later with one command:
npx sealed-env upgrade --to enterpriseββββββββββββββββ 1. push ββββββββββββββββ
β developer β ββββββββββββΆ β github β
ββββββββββββββββ ββββββββββββββββ
β 2. CI runs
βΌ
ββββββββββββββββ
β CI pipeline β paused, waiting for unseal
ββββββββββββββββ
β
β 3. notifies operator
βΌ
ββββββββββββββββ
β operator β 4. opens authenticator app,
β (you) β reads 6-digit TOTP code
ββββββββββββββββ
β
β 5. runs:
β sealed-env unseal --totp 482914 \
β --deploy-id <commit-sha>
βΌ
ββββββββββββββββββββββββββββββββββββββββ
β unseal token (60s lifetime, bound to β
β this specific deploy) β
ββββββββββββββββββββββββββββββββββββββββ
β 6. paste into CI form
βΌ
ββββββββββββββββ
β deploy runs β decrypts .env.sealed
β to prod β with master_key + token
ββββββββββββββββ
If the master key leaks AFTER the deploy β attacker still needs the operator's
TOTP. If the TOTP token leaks β useless for the next deploy (different commit).
The honest version. Different tools for different threat models β pick the one that matches yours.
| sealed-env | dotenv | dotenvx | Doppler | HashiCorp Vault | AWS Secrets Manager | jasypt | |
|---|---|---|---|---|---|---|---|
| Encryption at rest | β | β plaintext | β | β | β | β | β |
| Cross-stack (Node + Java) | β same wire format | n/a | Node only | language-agnostic (HTTP) | language-agnostic (HTTP) | language-agnostic (HTTP) | Java only |
| No external service required | β | β | β | β paid SaaS | β self-hosted server | β AWS | β |
| TOTP unseal at deploy time | β | β | β | β | β | β | |
| Replay protection (deploy-bound tokens) | β | β | β | β | β | β | |
| Public threat model | β | n/a | partial | NDA only | β | β | β |
| Zero runtime dependencies (Node) | β | β | β (8+ deps) | β SDK | β SDK | β SDK | n/a |
| Spring Boot autoconfiguration | β | n/a | n/a | community | community | community | manual |
| Memory wipe after key derivation | β | n/a | β | β | β | β | β |
| License | MIT | MIT | MIT | proprietary | MPL 2.0 | proprietary | Apache 2.0 |
| Cost | free | free | free | $0β$15/user/mo | free / Enterprise $ | $0.40/secret/mo | free |
dotenvβ solo dev, dev environment only, never production. Fine.dotenvxβ Node-only project, encryption at rest is enough, you trust your CI keystore. Fine.Doppler/AWS Secrets Managerβ you already pay for the platform, comfortable with vendor lock-in, want centralized rotation across many services. Good.HashiCorp Vaultβ you have ops capacity to run a Vault cluster, need fine-grained policies, and dynamic secrets (DB credentials per session). Heavy but powerful.jasyptβ Java-only project, encryption at rest is enough, you don't need cross-stack. Fine.sealed-envβ you want encryption at rest + a hard floor against compromised CI/CD (TOTP-bound deploys), no external service, and your stack is Node, Java/Spring Boot, or both. The defense ceiling is higher than dotenvx/jasypt; the operational cost is lower than Vault.
- Not a centralized secret manager (no rotation API, no audit log, no team policies).
- Not a substitute for HashiCorp Vault when you need dynamic per-session credentials.
- Not a fit if you want a SaaS dashboard.
If your team needs the Doppler/Vault feature set, use them. sealed-env is the right pick when you want a static, file-based, version-controllable encrypted secret with a higher security floor than dotenvx.
Pre-sealed apps you can clone and run in 60 seconds:
- π¦ examples/node-express β Node + Express server using
import 'sealed-env/config' - β examples/spring-boot β Java + Spring Boot 3 with the auto-config starter
The demo master key is checked in alongside each example so the apps work out of the box. It's public β never use it in real projects.
A desktop GUI on top of sealed-env, for the people who don't live in
the terminal. Built with Tauri 2 + React + TypeScript, with its own
Rust implementation of SEALED-ENV-V1 β the third stack alongside
Node and Java, validated against the same cross-stack test vectors.
What works today:
- Viewer β open a
.env.sealedfile, unlock with master / signing / TOTP, browse and mask values. - Init wizard β 5-step flow (folder β mode β source β keys β
review) for
basic,team, andenterprise. Auto-detects.env,.env.example,.env.sample,.env.template,.env.dist. QR code for enterprise authenticator pairing. Auto-appends.envto.gitignore. - Recent projects + settings panel (default mode, gitignore toggle, value masking, Argon2id parameter tuning).
Still pre-alpha β looking for testers and contributors. The Rust core
reads files sealed by the Node CLI and Java library byte-for-byte
(validated by decrypts_node_enterprise_vector and friends in CI).
β github.com/davidalmeidac/sealed-env-studio
β Full documentation index β start here if you're new.
- π Overview β what
sealed-envis and isn't - π Quick start: Node
- π Quick start: Java + Spring Boot
- π Enterprise mode walkthrough β TOTP + deploy binding
- π οΈ Operational guide β for sysadmins, managers, and founders (no code)
- βοΈ CI/CD + cloud recipes β GitHub Actions, GitLab, Bitbucket, CircleCI, Jenkins, Azure, AWS, GCP, Vercel, Railway, Docker, K8s
- π Project lifecycle β init β onboarding β deploy as one narrative
- π― Decrypt strategies β host-side vs in-process trade-off
- π¨ Incident response β playbook for a compromised host (β deadman switch warning)
- π File format anatomy β what's inside
.env.sealed - π Format specification β the canonical wire format (v1)
- π Secret patterns β canonical regex spec for tools like gitleaks / trufflehog
- π‘οΈ Security policy β how to report vulnerabilities
- π Threat model β which 2024-2026 attacks
sealed-envdefends against
- πͺ± Shai-Hulud defensive analysis β module-by-module mapping of TTPs to defenses
- π IOC table β consolidated indicators from public research
- π£οΈ Improvement roadmap β prioritized hardening for 0.2.2 / 0.3.0
- π‘ Future: supply-chain IOC feed bot β design brainstorm
CVE-2026-45091 was responsibly
self-disclosed and patched in 0.1.0-alpha.4. The disclosure has been
independently indexed and analyzed by:
| Source | What it is |
|---|---|
| NIST NVD | Official US National Vulnerability Database entry (CVSS 9.1, CWE-200 + CWE-522) |
| CVE.org | Canonical CVE record |
| GitHub Security Advisory | GHSA-x3r2-fj3r-g5mv (our advisory) |
| CVEReports | Independent technical analysis by Alon Barad (Software Engineer) |
| DailyCVE | Independent technical writeup |
| CIRCL Vulnerability-Lookup | European tracking (Luxembourg CERT) |
| Sploitus | Exploit feed aggregator entry |
| HORKimhab/CVE-2026-45091 | Third-party reproducible PoC published for research |
We list these because verifiable third-party coverage is part of a healthy disclosure track-record. The CVE itself is a fixed bug, not a current defect β see the advisory for the full timeline and remediation steps.
v0.1.0 β stable. The wire format (SEALED-ENV-V1) is frozen and
will remain readable forever. The public API is stable. Bug-fix and
non-breaking feature releases land as 0.1.x; breaking changes wait
for 0.2.0.
What's in 0.1.0:
- Three modes:
basic,team,enterprise(TOTP-bound deploys) - Node CLI (
init,encrypt,decrypt,get/set/edit/diff,exec,deploy,keychain) -
deploy --remotefor Model A host-side decrypt deploys - Cross-stack: Node + Java libraries reading the same wire format
- Spring Boot 3 starter (auto-config +
@Valuesupport) - OS keychain backend (Windows DPAPI, macOS Keychain, Linux secret-tool)
- 17 platform CI/CD recipes including OIDC federation
- Cryptographic test vectors validated cross-stack in CI
Roadmap:
- v0.1.x β
sealed-env doctor+install-hooks+ library-side.env.localautoload (non-breaking) - v0.2.0 β Java CLI (Maven-distributed) Β· Shamir Secret Sharing Β· sidecar pattern
- v0.3.0 β
memfd_secretLinux memory protection Β· heap-dump filter - v1.0 β Hardware-backed wrapping (TPM / Secure Enclave / YubiKey)
Companion projects:
- sealed-env-studio β desktop GUI (Tauri + React + Rust), Phase 1 viewer + Phase 2 init wizard implemented, cross-stack interop validated, pre-alpha
This is a security-sensitive project. Contributions are very welcome but please read SECURITY.md first. Crypto changes require explicit discussion.
MIT β David Almeida, 2026.
"Encrypt at rest. Authenticate at deploy. Wipe on read."